How to pass constants to a method? - java

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.

Related

Java final class with constant

I must define a class which all it does is hold constants.
public static final String CODE1 = "100";
public static final String CODE2 = "200";
Now I want use these values in other classes. Is it better to use this class as a static class or instantiate it ?
Thanks.
Note : I know enums but in this context, I must use a class.
Just to use the values, you certainly shouldn't instantiate the class. Just because you can access static members as if they were instance members doesn't mean it's a good idea.
If the class really only contains constants - and if you're sure that's a good idea, rather than those constants appearing within classes which are directly related to them - you should make it a final class with a private constructor, so that no-one can pointlessly instantiate it:
public final class Codes {
public static final String CODE1 = "100";
public static final String CODE2 = "200";
// Prevent instantiation
private Codes() {
}
}
Don's answer suggesting using an enum is a very good idea too - it means you can use Code in your API everywhere that you don't need the exact string representation, which prevents you from accidentally using non-code values.
Jons answer is correct, although I want to show you a solution with an enum.
There is a disadvantage in accessing its String value as you have to call Code.CODE1.text() instead of Code.CODE1.
public enum Code {
CODE1("100"), CODE2("200");
private String text;
Codes(String text) {
this.text = text;
}
public String text() {
return text;
}
}
java language spec and JVM spec allow you to do anything you wanted, whether instantiate a class or use final or use other way....
Just use Eclipse and try !
while there is some good practice, Jon Skeet's answer is one good practice.
Java Language is not support global variable
public class ComonFun {
public static final String CODE1 = "100";
public static final String CODE2 = "200";
public static String CODE1(){
return CODE1;
}
public static String CODE2(){
return CODE2;
}
}
implement
public class Main {
public static void main(String[] args) {
System.out.println(ComonFun.CODE1());
System.out.println(ComonFun.CODE2());
}
}
i think that you need simply to declare an interface, you won't need to specify the clause "public static final". and it can be usuable throgh the hall project.
Use them as static, don't go for instantiation.
Even use static import as a benefit.
package coma;
import static coma.ImportStatments.*;
public class UsingClass {
public static void main(String[] args) {
System.out.println(CODE1);
}
}
And the class with final variables would look like this:
package coma;
public class ImportStatments {
public static final String CODE1 = "100";
public static final String CODE2 = "200";
}

Modelling Game Difficulty

I wonder if my aproach into modelling difficulty level for my game is good.
public abstract class AbstractDifficulty {
public AbstractDifficulty() {
}
public abstract int enemyWaves();
public abstract int enemiesInWave();
public abstract long enemyWaveIntervalMilis();
}
And then several subclasses which implement those methods, for example.
public class EasyDifficulty extends AbstractDifficulty {
#Override
public int enemyWaves() {
return 1;
}
#Override
public int enemiesInWave() {
return 10;
}
#Override
public long enemyWaveIntervalMilis() {
return 500;
}
}
I wonder if there is a simpler way to do this, but the same easy and clean to use as this.
Edit: Could someone be so kind to explain to me why this question got minus votes. Is something wrong with this code, or my explanation ? Thanks.
Your design will do the job, but it seems what you want to have is a container class. So instead having a method for each value, have a (final) field with the value and a getter. They can be set e.g. in the constructor.
If your difficulty modes are known and few, consider having an enum, which are final and easier to use.
enum Difficulty {
EASY(1, 10, 5000),
MEDIUM(2, 15, 4000),
HARD(4, 20, 3500);
private final int enemyWaves;
private final int enemiesInWave;
private final long enemyWaveIntervalMilis;
Difficulty(int enemyWaves, int enemiesInWave, long enemyWaveIntervalMilis ){
this.enemyWaves = enemyWaves;
this.enemiesInWave = enemiesInWave;
this.enemyWaveIntervalMilis = enemyWaveIntervalMilis;
}
public int getEnemyWaves() {
return enemyWaves;
}
public int getEnemiesInWave() {
return enemiesInWave;
}
public long getEnemyWaveIntervalMilis() {
return enemyWaveIntervalMilis;
}
}
One alternative is to not have different difficulty classes, but just one difficulty class with different instances being the different difficulties (so, a class with attributes enemyWaves, enemiesInWave and enemyWaveIntervalMilis, and different instances with different settings).
Your solution looks fine. If you want to increase readability you can just remove the constructor from the abstract class, since that is created by Java as default anyway.
I also vote for an interface instead of an abstract class unless there is a specific reason to use abstract class.
I also feel that for the specific problem you do not need different classes, but rather different instances of the same class. In that case I would use the final fields set by constructor and then the methods return the values.
public class Difficulty {
final private int enemyWaves;
public Difficulty(final enemyWaves){ this.enemyWaves = enemyWaves; }
#Override
public int enemyWaves() {
return this.enemyWaves;
}
}

Is there a certain benefit in declaring an object using a class and assign it to another class?

During a Java course in my University we teach this example. While I certainly understand how this works, I fail to imagine a real life example where this practice might be useful. In my eyes it makes the code harder to understand. More specifically, is there a certain benefit in declaring an object using a class and assign it to another class (Small smallBig = new Big();) and can you give me a simple scenario where this practice might be useful?
The code:
public class Small {
public int value;
public Small() {value = 10;}
public int getValue() {return value;}
}
public class Big extends Small {
public int value;
public Big() {value = 40;}
public int getValue() {return value-10;}
}
public class Main {
public static void main (String args[]) {
Small small = new Small();
Small smallBig = new Big();
Big big = new Big();
System.out.println(small.getValue());
System.out.println(smallBig.getValue());
System.out.println(big.getValue());
System.out.println(small.value);
System.out.println(smallBig.value);
System.out.println(big.value);
small = (Small) big;
System.out.println(small.getValue());
System.out.println(small.value);
big = (Big) small;
System.out.println(big.getValue());
System.out.println(big.value);
}
}
The output:
10
30
30
10
10
40
30
10
30
40
Creating a method that operates on both Bigs and Smalls will help to illustrate the point better.
Assuming the same class definitions you already used in the question, you can create a method that prints both getValue() and value. Because Big extends Small, you need only one method.
public void printValues(Small val) {
System.out.println("getValue() == " + val.getValue());
System.out.println("value == " + val.value);
}
If you didn't have that relationship, and ability to assign Big objects to Small variables (remember: passing a value to a method is the same as assigning a variable), you'd need to have two different methods to handle this situation.
It helps to think of the extends keyword as meaning A Big is a more specific type of Small. In general, it's best to write methods that handle things using the least specific type that you can, because it will allow that method to handle situations you haven't even imagined yet.
For example, suppose that somewhere down the line, somebody decided to write
class Medium extends Small {
public Medium() {value = 20;}
public int getValue() {return value-5;}
}
The printValues() method can already handle this class, even though we didn't know about Mediums when we wrote it.
I think in this senario it'd be useful:
public class Person{
Mobility mobility;
Person(Mobility mobility){this.mobility = mobility;}
}
public class Mobility{
int speed;
public Mobility(int speed){this.speed = speed;}
}
public class Car extends Mobility{
public Car(int speed){super(speed);}
}
public class Main {
public static void main (String args[]) {
Car ferrari = new Car(1000);
Person john = new Person(ferrari);
}
}
Hope i could help you.
Well in this case you are using getValue as Template method "http://en.wikipedia.org/wiki/Template_method_pattern"
Let take you example with little twist
public class Small {
public int value;
public Small() {value = 10;}
public int getValue() {// this method fetches data from database}
}
public class Big extends Small {
public int value;
public Big() {value = 40;}
public int getValue() {//this method fetches data from xml}
public class Big2 extends Small {
public int value;
public Big() {value = 40;}
public int getValue() {//this method fetched data from some server}
}
As u can see the implementation of getValue is changing. Each sub class provides its own implementation of getValue.
Thus it gives my super class an opportunity to use different implementation of this method at run time (in you case). I Hope it makes it clear. Have a look at Template method pattern , you will get a better idea.

more enum in interface

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.

Determine which subclass to choose by accessing static variables from the Class object

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.

Categories