Check this example:
public interface IConstants {
public enum Levels {
LOW("30 points"), MEDIUM("50 points")
};
public enum Cars {
PORSCHE("250 km/h"), FORD("180 km/h")
}
}
I'd like to have an interface like this, because I want to access my enums this way:
String level = IConstants.Levels.MEDIUM;
String car = IConstants.Cars.PORSCHE;
The compiler shows this message:
constructor IConstants."enum name" is undefined.
Solved this way :
public class Constants {
public static class Levels {
public static String LOW = "30 points";
public static String MEDIUM = "50 points";
};
//... other classes
}
-useful for me in (my case) to have a "tree" in my constants, every constant starting by keyword Constants then subcategory and then value -> Constants.Levels.LOW.
//critize it if it's very bad practise, i agree all comments
-another maybe good thing that there will be all constants in one class
Like Boris the spider told you in comment declaring constants in interfaces is an anti pattern. However your problem comes from the fact that you are passing a String to any instance of your enum but you are not declaring a constructor for this
public enum Levels {
LOW("30 points"), MEDIUM("50 points")
private final String pts;
private Levels(String pts) {
this.pts = pts;
}
public String getPoints() {
return pts;
}
};
This should work.
You are missing constructors in both enums. A private variable and the constructor is required, e.g.
public enum Levels {
private String name;
public Levels(String name) {
this.name = name;
}
}
Also it is considered bad practice to put inner classes, constants in interfaces.
To add to other answers, it will still not compile after an enum constructor is added, because you are assigning a String variable to a Levels or Cars. Please use:
String level = IConstants.Levels.MEDIUM.methodToAccessString();
String car = IConstants.Cars.PORSCHE.methodToAccessString();
Replacing methodToAccessString() with whatever you call it, of course.
Related
This question already has answers here:
Why different class files are created for each enum type if they have constant-specific method?
(2 answers)
Closed 4 years ago.
I am learning the various options that an enum can provide to us. I have learnt about constructors, methods and overriding methods in it.
The code samples are below.
I have one question though.
In this case, getClass() returns class enumData.WeekEnumElaborate$1, enumData.WeekEnumElaborate$2 and so on until enumData.WeekEnumElaborate$8
But, when the enum is a simple one, with just constants declared, getClass() returns enumData.WeekEnumElaborate.
Kindly explain me this binary notation.
Here is a enum that I have defined.
package enumData;
public enum WeekEnumElaborate {
SUNDAY("SUN") {
public String getDescription() {
return this.getShortForm().concat(" Funday");
}
},
MONDAY("MON") {
public String getDescription() {
return this.getShortForm().concat(" Moot");
}
};
private final String shortForm;
private WeekEnumElaborate(String shortForm) {
this.shortForm = shortForm;
}
public String getShortForm(){
eturn this.shortForm.toLowerCase();
}
public abstract String getDescription();
}
And here is a class that I am testing.
package enumData;
public class TestWeekEnumElaborate {
public static void main(String[] args) {
WeekEnumElaborate[] days = WeekEnumElaborate.values();
for (WeekEnumElaborate day : days) {
System.out.println(day.name());
System.out.println(day.getClass());
System.out.println(day.getDeclaringClass());
}
}
}
When you give an enum different behaviour to the outer enum class, you are effectively defining an anonymous static inner class which is a subclass of the base enum class.
The names of these nested classes are named same way anonymous inner classes are named. Ie outer class + $ + counter.
This allows each enum to have different method implementations for the same signature.
You are currently defining anonymous inner classes in your enum definition, which is the part I was referring to when I asked you to not write code like this. To elaborate, the way I would implement your original enum would be something like
public enum WeekEnumElaborate {
SUNDAY("SUN", "Funday"), MONDAY("MON", "Moot"), TUESDAY("TUE", "Terrible"),
WEDNESDAY("WED", "Weed"), THURSDAY("THUR", "Terrific"), FRIDAY("FRI", "Fairy"),
SATURDAY("SAT", "Jollyday"), R$00("R$00", "RX100 Day");
private final String shortForm;
private final String description;
private WeekEnumElaborate(String shortForm, String description) {
this.shortForm = shortForm;
this.description = description;
}
public String getShortForm() {
return this.shortForm.toLowerCase();
}
public String getDescription() {
return new StringBuilder(getShortForm()).append(' ').append(this.description).toString();
}
public String getFurtherDescription(String desc) {
if (this == MONDAY) {
return "I do not want to work on this day!!!!";
}
return getDescription();
}
}
No anonymous classes required, and it is significantly shorter and easier to reason about.
I have this classes:
package util;
public final class Constant {
private Constant() {
throw new AssertionError();
}
public static class Product {
public static final String CODE = "Product";
public static final String A = "product_5g2g";
public static final String B = "product_a45h";
public static final String C = "product_a3ag";
//more constants..
}
public static class Employee {
public static final String CODE = "Employee";
public static final String A = "employee_1g3f";
public static final String B = "employee_h52d";
public static final String C = "employee_h5d2";
//more constants..
}
public static class Client {
public static final String CODE = "Client";
public static final String A = "client_h5ad";
public static final String B = "client_1df1";
public static final String C = "client_6g23";
//more constants..
}
}
and:
package util;
import util.Constant.*;
public class Main {
public void run() {
if (isSelected(Product.CODE)) {
if (isSelected(Product.A) || isSelected(Product.B)) {
//do something
}
compute(Product.C);
//more similar instruction that use constants from Product class
}
if (isSelected(Employee.CODE)) {
if (isSelected(Employee.A) || isSelected(Employee.B)) {
//do something
}
compute(Employee.C);
//more similar instruction that use constants from Employee class
}
if (isSelected(Client.CODE)) {
if (isSelected(Client.A) || isSelected(Client.B)) {
//do something
}
compute(Client.C);
//more similar instruction that use constants from Client class
}
}
public boolean isSelected(String s) {
return true;
}
public void compute(String s) {
}
}
As you can see, this block of code
if (isSelected(StaticClass.CODE)) {
if (isSelected(StaticClass.A) || isSelected(StaticClass.B)) {
//do something
}
compute(StaticClass.C);
//more similar instruction that use constants from Product class
}
is repetitive, but can't put it in a separate method because java don't permit a static class as a parameter public void method(StaticClass) {}.
How can I refactor the above code? My first thought was to make Singletons that extend a base class, or implement an common interface. There is a better solution?
You should look into using polymorphism here. Example: instead of doing
if (X) {
doY();
}
"good" OO looks much more like:
Y y = getMeSomeY();
y.doTheY();
Where getMeSomeY() returns you exactly that what is required (so Y could be an interface; and that method provides different implementations of that interface which all do slightly different things).
The point is: you wrote procedural code, where you ask something, to then make a decision about it. Good OO favors the opposite (called tell don't ask).
You start by ... not making everything flat strings. By doing so, you give up on the whole "static typing" thing. If your code is making decisions only on strings, why are you programming in Java? You can very well use a non-typed language than. So, at least learn about Java enums; and use those. But please understand: enums are not the real answer here. They would just help to make your code a bit better.
The real problem here is that you want to write code doing these if (x) then y all over the place.
You might have guessed by now: there is no easy answer here. What I would do: first, step back. And have a in-depth look into your design. The code you have right now indicates to me that your underlying object model is far from "helpful". And that is the whole point of OO: you create classes and objects that help you to write clean, elegant code. But when your base design isn't supporting that; then there is no point in trying to refactor the code that came out of that. Because the ugliness of your code is just a symptom; the root cause lies in your design underneath.
What you are looking for is an Enum. Redefine all your classes as Enums instead. For example, you can redfine the Product class as follows :
public enum Product {
CODE("Product"),
A("product_5g2g");
private String value;
//define others constants in a similar fasion
public Product(String value) {
this.value = value;
}
}
Enums can be passed as method parameters. In your particular example, you can do this :
public void method(Constants.Product product) {
}
That said, you should definitely look into an alternative way to achieve your objective. Take a look at Replacing conditionals with Polymorphism for starters.
At present I have a class called TestEnum. In my main method I can work with firstEnum and secondEnum without needing to specify that firstEnum belongs to GroupA and secondEnum belongs to GroupB - the code in TestEnum sorts this out.
Suppose that either firstEnum or secondEnum could be associated with any of the three SubGrouping enum. I want to be able to make this association from within my main method. It is clear I can't use the same approach as with Grouping since GroupA is allocated to firstEnum from within TestEnum.
public enum TestEnum {
firstEnum (Grouping.GroupA),
secondEnum (Grouping.GroupB);
private Grouping group;
TestEnum(Grouping group) {
this.group = group;
}
public enum Grouping {
GroupA, GroupB;
}
public enum SubGrouping {
SubGroup1, SubGroup2, SubGroup3;
}
}
How do I do this? To be more concrete, it would be good to construct an object such as:
TestEnum enumWithinMainMethod = TestEnum.firstEnum(SubGrouping.SubGroup1)
The desired behaviour of this instance is that it belongs to both SubGroup1 as well as GroupA. Then from such an instance it would be good to have the functionality, for example:
switch(enumWithinMainMethod) {
case firstEnum:
// Do something associated with firstEnum
case secondEnum:
// Do something associated with secondEnum
default:
// ...
}
Double think before going this approach. Enum is aimed to be static, constant and with finite set of values. What you are doing here is making Enum no longer constant (as you are changing/initializing it in runtime).
I believe there are other way to do, for example, review if it is actually required to have the relationship determined in runtime? Can't it be defined in compile-time? You may also having a TestEnum-to-SubGroup map, instead of dynamically construct the content of TestEnum.
Anyway, although it is not preferable, it is technically possible in Java.
Of course you cannot delay the "construction" of enum until your main() logic, but you can have enum constructed as normal, and change the internal state.
// Mind the naming convention
public enum TestEnum {
FIRST_ENUM(Grouping.GROUP_A),
SECOND_ENUM (Grouping.GROUP_B);
private Grouping group;
private SubGrouping subGrouping;
TestEnum(Grouping group) {
this.group = group;
}
public void setSubGrouping(SubGrouping subGrouping) {
this.subGrouping = subGrouping;
}
public enum Grouping {
GROUP_A, GROUP_B
}
public enum SubGrouping {
SUB_GROUP_1, SUB_GROUP_2, SUB_GROUP_3;
}
}
Then in your main(), do something like
TestEnum.FIRST_ENUM.setSubGrouping(TestEnum.SubGrouping.SUB_GROUP_1);
TestEnum.SECOND_ENUM.setSubGrouping(TestEnum.SubGrouping.SUB_GROUP_2);
By doing so, you can define the subgrouping of your enum in your main()
Once again, this is NOT PREFERABLE.
You cannot call enum constructors from outside of an enum. You could use a class to get this behaviour.
How about something like this? (The generics are not required, but it does open up the Groupable class to multiple types of groupings.)
public enum Grouping { GroupA, GroupB; }
public enum SubGrouping { SubGroup1, SubGroup2, SubGroup3; }
public class SubGroupable<G extends Enum<G>,S extends Enum<S>> {
private G mainGroup;
private S subGroup;
public Groupable(G group, S subGroup) {
this.mainGroup = group;
this.subGroup = subGroup;
}
public G getGroup() { return mainGroup; }
public S getSubGroup() { return subGroup; }
}
Usage
SubGroupable<Grouping, SubGrouping> g
= new SubGroupable<>(Grouping.GroupA, SubGrouping.SubGroup2);
switch (g.getGroup()) {
case Grouping.GroupA:
//
break;
case Grouping.GroupB:
//
break;
}
You could also create two final groupings:
public final Grouping FIRST_GROUP = Grouping.GroupA;
public final Grouping SECOND_GROUP = Grouping.GroupB;
This way you can use those constants in your case blocks.
switch (g.getGroup()) {
case FIRST_GROUPING: // etc
}
I am trying to implement an interface in Java to use different types of databases for one application.
My though was to create an abstract class with the common interface and two static variables which are then overwritten by the subclasses. I then wanted to add a Class[] List with the classes of all available subclasses to the abstract class as well as a couple of functions that allow the determination of the correct class to be used.
The goal is to first get a list of all available database types and let the user choose one. Afterwards another function should translate the name (which could be localized) to the IDENTIFIER which is specified in the subclass. Finally a third function allows the instantiation of an object by giving such an IDENTIFIER.
My abstract class would look something like this:
public abstract class DataBase {
public static final IDENTIFIER = "";
public static final NAME = "";
private static final Class[] dbTypes = new Class[]{PostgreSQL.class, MySQL.class};
public static String[] getNameList() {
String[] names = new String[dbTypes.length];
for(int i = 0; i < dbTypes.length; i++){
names[i] = dbTypes[i].NAME; //Cannot access the static variable this way.
}
return names;
}
public static String getIdentifierForName(String name) {
for(int i = 0; i < dbTypes.length; i++){
if(name.equals(dbTypes[i].NAME){
return dbTypes[i].IDENTIFIER;
}
}
return "";
}
public static DataBase getInstanceOf(String identifier) {
for(int i = 0; i < dbTypes.length; i++){
if(identifier.equals(dbTypes[i].IDENTIFIER) {
return dbTypes[i].newInstance();
}
}
return null;
}
}
The Child classes would look something like this:
public class MySQL extends DataBase {
public static final IDENTIFIER = "ab.cde.MySQL";
public static final NAME = "MySQL";
...
}
public class PostgreSQL extends DataBase{
public static final IDENTIFIER = "ab.cde.PostgreSQL";
public static final NAME = "PostgreSQL";
...
}
My problem now is, that I cannot access the static variables from the Class object. Obviously the dbTypes list does not contain any typed classes. I tried changing the type of the Array to Class<? extends DataBase>, but I get an error Cannot create a generic array of Class<? extends DataBase> I also tried checking the classes with isAssignableFrom() and then casting the class, but I was still not able to access the static variables.
For now I have two solutions which are working:
Hardcode all existing subclasses into each function if(PostgreSQL.NAME.equals(name)){...}etc.
However, if I add new subclasses, I only want to have to add them at one point in my implementation.
Instead of using a Class[] array, I can use an array of DataBase[] with instances of each class. However, I would think this is bad practice to instantiate each available DataBase subclass, even though I only need one in the end.
Since I have never done such a thing before I might also be approaching the problem completely wrong. Maybe I am missing the correct way in which something like this is usually done?
Thank you for your help.
There are no "abstract properties" in Java. You have to create two astract methods in the DataBase class, like this:
public abstract class DataBase {
// No "abstract propeties"
public abstract String getDBName();
public abstract String getDBIdentifier();
// etc etc...
}
and then, in each subclass:
public class MySQL extends DataBase {
public static final IDENTIFIER = "ab.cde.MySQL";
public static final NAME = "MySQL";
#Override
public String getDBName() {
return NAME;
}
#Override
public String getDBIdentifier() {
return IDENTIFIER;
}
// etc etc...
}
When using the classes, you can just cast to DataBase (not MySQL or PostgreSQL) and call the two abstract methods.
Therefore, in order to solve your "pick a database class" problem, I would create a configuration file that contains the names of the databases and the corresponding class, and instantiate it with reflection (newInstance()) as needed.
As an alternative, you can use reflection to access the static variables like Nikita's answers suggested, or you can just use the name of the class as the identifier of the database it supports, like this (not tested):
public abstract class DataBase {
private static final Class[] dbTypes = new Class[]{PostgreSQL.class, MySQL.class};
public static Class getDBClass(String type) {
for (Class c : dbTypes) {
if (c.getSimpleName().toLowerCase().equals(type.toLowerCase())) {
return c;
}
}
return null;
}
public static Set<String> getSupportedDB() { // <-- you populate a dropdown menu with this
Set<String> supported = new HashSet<String>();
for (Class c : dbTypes) {
supported.add(c.getSimpleName());
}
return supported;
}
// etc etc...
}
However, I don't like this solution and I would not use it.
You can use reflection to get values for each class:
public static String[] getNameList(){
String[] names = new String[dbTypes.length];
for(int i=0; i<dbTypes.length; i++){
Field f = dbTypes[i].getField("NAME");
names[i] = f.get(null);
}
return names;
}
But it might be slow.
Also I'd suggest to create separate enum DBRegistry that will contain names, identifiers and classes:
public enum DBRegistry {
MYSQL("ab.cde.MySQL", "MySQL", MySQL.class),
POSTGRESQL("ab.cde.PostgreSQL", "PostgreSQL", PostgreSQL.class);
private String name;
private String identifier;
private Class<?> dbClass;
private DBRegistry(String identifier, String name, Class<?> dbClass) {
this.identifier = identifier;
this.name = name;
this.dbClass = dbClass;
}
// Getters...
}
You can iterate on all items in registry using DBRegistry.values
Not tested, but I would suggest something like this. You could register databases by calling DataBase.registerDataBase(new DataBase(...))); which may be invoked from the main file.
public class DataBase {
private final static List<DataBase> INSTANCES = new ArrayList<DataBase>();
private final String identifier;
private final String name;
private final Class<?> dbType;
public DataBase(String identifier, String name, Class<?> dbType) {
this.identifier=identifier.toString();
this.name=name.toString();
this.dbType=dbType;
}
String getIdentifier() {return identifier;}
String getName() {return identifier;}
Class<?> getDbType() {return dbtype;}
public synchronized static void registerDatabase(DataBase database) {
database.getClass();
INSTANCES.add(database);
//may check if already registered and either fail or replace it
}
public synchronized static List<DataBase> getNameList() {
return new ArrayList<DataBase>(INSTANCES);
}
public synchronized static List<String> getNameList() {
List<String> names = new ArrayList<String>(INSTANCES.size());
for (Database db:INSTANCES) names.add(db.getName());
return names;
}
public synchronized static String getIdentifierForName(String name) {
for(DataBase db:INSTANCES){
if(name.equals(db.getName())) return db;
}
return null;
}
public synchronized static DataBase getInstanceOf(String identifier) {
for(DataBase db:INSTANCES){
if(identifier.equals(db.getIdentifier())) return db;
}
return null;
}
}
}
I would advise to keep it simple, never more than necessary to utilize in the actual application. It is easier to extend things than to re-factor code to accomodate for additional complexity. Most of the stuff you mention are merely artefacts of your problem solving, not the actual requirements of your application per se. And it so happens, that a modern object-oriented language has everything you need, and you can implement a good design without reflection and without resorting to static properties and string identifiers.
Remember to rely on the compiler rather than runtime for whatever you know in advance - anything that is known not to change from one application run to another, does not need reflection, because it does not involve runtime variables! I would go for interfaces, classes implementing them, and more importantly the Factory pattern to abstract using these classes:
interface Database
{
void query(String sqlString);
}
class MySQLDatabase implements Database
{
public void query(String sqlString)
{
}
}
class PostgreSQLDatabase implements Database
{
public void query(String sqlString)
{
}
}
class DatabaseFactory
{
Database connectDatabase()
{
/// F.e. return new MySQLDatabase();
}
}
The whole "database abstraction layer" has been done to death already anyway, giving birth to DBA, ODBC and other software stacks that solve your problem. You should let yourself be inspired by these, unless you are sure your particular way of solving this yields advantages that can be proven. If you want to go about this in a professional way, of course. If you want to educate yourself, by all means, use reflection, strings in place of more specific objects, and tight-coupling instead of aggressive modularity.
Can anybody explain me why below code is working on private member variable?
public class Person implements Comparable<Person> {
private String firstName;
public Person(String firstName) {
this.firstName = firstName;
}
#Override
public int compareTo(Person o) {
return firstName.compareToIgnoreCase(o.firstName); // why does it work? } }
}
}
EDIT Why o.firstName is getting compile ? where firstName is private variable.
The access modifiers control access per class rather than per instance. So, methods of class T can access all members (even private) of other class T's instances.
The Access Control from JLS 7 link for the curious. It says, "Note that accessibility is a static property that can be determined at compile time; it depends only on types and declaration modifiers."
Because private variables are visible within the class that declares them, and o is a Person.
The method "compareTo" is implemented in the "Person" class which naturally has access to it's private members. You override the method from the interface Comparable. So you are working with the same class in both cases.
Because objects of the same class can access each others private properties. This does not entirely break the separation of concerns because the code for such accesses must be in the same class so the class is still responsible for the property.
You are using the private members inside the class, that declares them, which is perfectly ok.
The declaring class always has access to all of its members, regardless of which instance of the class the members belong to.
Thus the following code compiles and works.
public class AClass {
private String name;
public AClass(String n) {name = n;}
public void mock(AClass other) {
System.out.pritln(this.name + ": \"" + other.name + " smells.\"");
}
public static void main(String[] args) {
AClass a = new AClass("Bully");
AClass b = new AClass("Nemesis");
a.mock(b);
}
}