1

I have a program that handle the math operator(+,*,-,/).I have an interface Operator that have a calculate method like so:

public interface Operator
{
    double calculate(double firstNumber,double secondNumber);
}

I have four class (Plus,Minus,Divide,Multiply) that implement the Operator interface like so :

public class Plus implements Operator
{   
    public double calculate(double firstNumber,double secondNumber)
    {
        return firstNumber + secondNumber;
    }
}

public class Minus implements Operator
{
    public double calculate(double firstNumber,double secondNumber)
    {
        return firstNumber - secondNumber;
    }
}

And so on...

I use Map to handle the operator :

static Map<String,Operator> operatorMap = new HashMap<String,Operator>();
static
{
    operatorMap.put("+", new Plus());
    operatorMap.put("-", new Minus());
    operatorMap.put("*", new Multiply());
    operatorMap.put("/", new Divide());
}

double output = operatorMap.get(op).calculate(firstNumber,secondNumber);

I should change the program like so:

I have a folder(myfolder).Every one can get the interface and implement own operator and put .class file in myfolder.My program should also work.It means dependency to (+,*,-,/) should remove from my program. For Example some one get the Operator interface and implement % and put .class file in my folder my program still should work(Map implementation must change) Can anyone help me? I am so appreciate.

soha
  • 115
  • 1
  • 12
  • 1
    What is your question? Your codes looks OK and the setup you described with people dropping in class files of other operators also sounds fine. – Tim Biegeleisen Aug 24 '15 at 04:50
  • 1
    Probably because the teacher wrote that part -- he's lost when it comes to actually doing something on his own. – Blindy Aug 24 '15 at 04:52
  • @ Tim Biegeleisen imagine I implement the % (my program dose not support %) and compile my own code for % and put .class file in myfolder(other .class file alse is in this folder) my program from .class file should determine which operator should select – soha Aug 24 '15 at 04:55
  • So what you mean is that you will create a new class for new operator, and the program should automatically pick this up. right? – Tarun Gupta Aug 24 '15 at 05:00
  • @ Tarun Gupta Yes.I put last implementation of Operator(Plus.Minus,Divide,Multiply) in myfolder(.class files) now I implement % and put .class also in myfolder my program should dynamically chose the correct operator(dependency to Map should remove) – soha Aug 24 '15 at 05:06
  • So someone writes a class that implements "modulo". There's a now a .class file in the folder for this. But what is going to tell your program that the `"%"` string is associated with it? Just writing the new operator class isn't going to be enough--_somewhere_, _something_ has to tell the app what the operator is. You'll need to provide an idea of what that is supposed to happen. – ajb Aug 24 '15 at 05:16

3 Answers3

1

So what you mean is that you will create a new class for a new operator, and the program should automatically pick this up. If that is the case you can use Reflection API to iterate through the available classes that implement Operator interface. and then add them into your map.

To remove the dependency to hashmap you can add a new method in your Operator interface something like this :

public interface Operator
{
  double calculate(double firstNumber,double secondNumber);
  char getSign();
}

All the classes like Plus, Minus will return a char that maps to their sign.

public class Plus implements Operator
{   
  public double calculate(double firstNumber,double secondNumber)
  {
     return firstNumber + secondNumber;
  }
  public char getSign()
  {
     return '+';
  }
}

Next, in your calculate(char operator, int operand1, int operand2) method you can first iterate through all the classes that implement Operator interface (using reflection) then call get sign and compare it with operator argument passed to this method, if the sign matches with the operator, pass the operand to Operator.calculate() method. To get all the classes that implement Operator interface you can use the following code :

Reflections reflections = new Reflections("mypackage");
Set<Class<? extends Operator>> classes = reflections.getSubTypesOf(Operator.class);

Hope you got the idea now.

Tarun Gupta
  • 1,629
  • 1
  • 22
  • 39
  • Is with the use reflection dependency to Map remove? – soha Aug 24 '15 at 05:10
  • Yes, To remove dependency to map you can follow this approach, also add a new method in your Operator interface – Tarun Gupta Aug 24 '15 at 05:15
  • @ Tarun Gupta I am so appreciate for your help.Thanks alot – soha Aug 24 '15 at 05:32
  • Sure, please accept the answer if when are able to make it work. – Tarun Gupta Aug 24 '15 at 05:35
  • @ Tarun Gupta Sry how can I accept the answer? I am new with stackoverflow – soha Aug 24 '15 at 05:43
  • @soha, it should be noted that `Reflections` is not the part of Java Reflection API, but third-party library. So you must add this library to your project in order to to use this solution. – Tagir Valeev Aug 24 '15 at 06:05
  • @ Tarun Gupta Sorry I use your code but java did not determine Reflections and I should download the library .Can we use java own Reflection and don't download library?because my program should work just with java libraries – soha Aug 24 '15 at 07:44
  • Try the method described by @tagir-valeev or see these answers: http://stackoverflow.com/a/15519745/1898397 http://stackoverflow.com/a/21840860/1898397 – Tarun Gupta Aug 24 '15 at 08:21
0

You can use factory pattern to implement this if you're using java 8 then String can be used as part of switch case else you will need to try char or int:-

public class MyFactory {
    private MyFactory() {
    }

    public static Operator getOperator(String operator) {
        switch (operator) {
            case "+":
                return new Plus();
            case "-":
                return new Minus();
            case "*":
                return new Multiply();
            case "/":
                return new Divide();
            case "%":
                return new Modulo();
        } 
    }
}

And then call:-

Operator op = MyFactory.getOperator("+");
op.calculate(firstNumber,secondNumber);
Tom
  • 16,842
  • 17
  • 45
  • 54
Rahul Yadav
  • 1,503
  • 8
  • 11
  • 1
    @ Rahul Yadav I use java 6 .Sry in your program dependency also exist.my program should automatically chose the best .class – soha Aug 24 '15 at 05:08
0

You can use an URLClassLoader to load classes dynamically from given folder. Note that you also need to specify somehow the operator name. Suppose there's a special method in the interface like this:

public interface Operator
{
    String getOperator();

    double calculate(double firstNumber,double secondNumber);
}

And you implement it like this:

public class Plus implements Operator
{   
    @Override
    public double calculate(double firstNumber,double secondNumber)
    {
        return firstNumber + secondNumber;
    }

    @Override
    public String getOperator() {
        return "+";
    }
}

Then you can load all the operators from the given folder like this:

Map<String, Operator> initOperators(File folder) {
    File[] files = folder.listFiles();
    Map<String, Operator> operators = new HashMap<String, Operator>();
    if(files == null)
        return operators;
    URLClassLoader cl;
    try {
        cl = new URLClassLoader(new URL[] {folder.toURI().toURL()});
    } catch (MalformedURLException e) {
        return operators;
    }
    for(File file : files) {
        String name = file.getName();
        if(name.endsWith(".class")) {
            try {
                String className = name.substring(0, name.length()-".class".length());
                Operator op = cl.loadClass(className)
                                .asSubclass(Operator.class)
                                .newInstance();
                operators.put(op.getOperator(), op);
            } catch (ClassNotFoundException e) {
            } catch (InstantiationException e) {
            } catch (IllegalAccessException e) {
            } catch (ClassCastException e) {
            } catch (NoClassDefFoundError e) {
            }
        }
    }
    return operators;
}

Exceptions are just ignored in my example, You may decide to handle them in more appropriate way.

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334