从工厂中的字符串参数获取正确的对象

时间:2015-09-09 15:11:16

标签: java oop design-patterns calculator

我一直试图找出是否有办法将字符串传递给工厂或构造函数并创建正确的对象,而不必将字符串映射到对象,或者没有一堆if / else语句或转换声明。

请记住,这是一个简单的示例,因此我可以将我学到的内容应用于网络应用等更复杂的情况。

让我们以一个简单的计算器应用程序,用JAVA编写,作为一个例子

假设这是命令行,并且一个人可以传入3个值

- first number
- math operation (+ , - , / , x)
- second number

我们有一个界面

public interface ArithmeticOperation {
  public double performMathOperation(double firstNum, double secondNum);
}

有4个实现它的类

public class AdditionOperation implements ArithmeticOperation {
  public double performMathOperation(double firstNum, double secondNum) {
    return firstNum + secondNum;
  }
}

// public class Subtraction operation returns firstNum - secondNum
// etc...

我们有实际的Calculator类和UserInput类

public class UserInput {
  public UserInput(double firstNum, double secondNum, String operation) {
    this.firstNum = firstNum;
    // etc...
  }
}
public class Calculator {
  public UserInput getInput() {
    // get user input, and return it as a UserInput object
    // return a UserInput object
  } 
  public performOperation() {
    UserInput uInput = getInput();
    double answer = ArithmeticOperationFactory
      .getSpecificOperation(uInput.operation)
      .performMathOperation(uInput.firstNum, uInput.secondNum);
    // send answer back to user
  }
}

最后,问题主要围绕的地方,工厂

public class ArithmeticOperationFactory {

  public static ArithmeticOperation getSpecificOperation(String operation) {
    // what possibilities are here?
    // I don't want a map that maps strings to objects
    // I don't want if/else or switch statements
    // is there another way?

  }
}

另外,如果有更好的方法来构建这样的系统或可以应用的设计模式,请分享。我真的想学习一些好的面向对象设计

4 个答案:

答案 0 :(得分:1)

你要求的是一个映射操作,因为你有一个String作为输入,你想要一个Object实现和接口(ArithmeticOperation)。如果mpa剂量不适合你需要你必须"配置"以不同的方式进行映射,这是我的建议: 将界面更改为

public interface ArithmeticOperation {
    public double performMathOperation(double firstNum, double secondNum);
    public double getName();
}

您的添加操作将产生以下结果:

public class AdditionOperation implements ArithmeticOperation {
    public double performMathOperation(double firstNum, double secondNum) {
        return firstNum + secondNum;
    }
    public double getName() {
        return "+";
    }

}

在方法工厂中,您只需找到实现ArithmeticOperation接口的所有类;类似的东西:

public class ArithmeticOperationFactory {
    private List<ArithmeticOperation> availableOperations=null;
    //to be called at application startup
    public static void findAvailableOperations() {
        // a strategy for finding implementations that fills
        // availableOperations
    }
public static ArithmeticOperation getSpecificOperation(String operation) {
  for (ArithmeticOperation arithmeticOperation : availableOperations) {
      if (operation.equalsIngoreCase(arithmeticOperation.getName)) {
         return arithmeticOperation;
      }
  }

}

您可以使用以下方法来实现findAvailableOperations:

如果您使用的是Spring,则可以获取api getBeansOfType并检索所有实现(我假设您将具体操作配置为Spring bean)。

如果您不使用spring,则可以扫描类路径以查找实现接口的类;您可以从this projectthis one开始。

另一种解决方案是将实现类名称放入文件(.properties,.xml,.json等),读取类名并通过反射创建它们。

答案 1 :(得分:1)

有一种不同的方式。我不确定它会更好。

我们必须返回界面并添加另一个方法,以便类可以识别操作符。

public interface ArithmeticOperation {
    public boolean isOperator(String operator);
    public double performMathOperation(double firstNum, double secondNum);
}

我们编写如下具体方法:

public class AdditionOperation implements ArithmeticOperation {
    @Override
    public boolean isOperator(String operator) {
        return operator.equals("add");
    }

    @Override
    public double performMathOperation(double firstNum, double secondNum) {
        return firstNum + secondNum;
    }
}

我们将所有ArithmeticOperation类放在List

List<ArithmeticOperation> operations = new ArrayList<>();
operations.add(new AdditionOperation());
...

最后,我们执行这样的操作。

double answer = 0D;
for (ArithmeticOperation operation : operations) {
    if (operation.isOperator(currentOperator) {
        answer = operation.performMathOperation(firstNum, secondNum);
        break;
    }
}

答案 2 :(得分:1)

没有比你以前见过的解决方案好得多的方法。你只能稍微优雅一点。从本质上讲,你可以拥有:

一堆if / else / switch(可能最不优雅但很快)

if("typeAsString").equals("operation"){
    return new SomeType()
}

地图

Map<String, Class<? extends YourType> map = new HashMap<>();

您可以通过依赖注入使其更好一些,或者您可以使每个子类在此映射中添加自己的条目。我倾向于将配置远离工厂类并将其移至子类。

责任链

您必须创建所有子类型的Collection。每个子类型都必须有isItCorrectSubtype()之类的方法。客户端类必须遍历整个集合并检查哪个实现是正确的

@Autowired
List<InterfaceOfYourTypes> allSubtypes;

..

public void doStuff(){
    for(InterfaceOfYourTypes subtype: allSubtypes){
        if(subtype.isCorrectSubtype()){
            //create instance
        }
    }
}

答案 3 :(得分:0)

您可以使用像这样的工厂

public class ArithmeticOperationFactory {
    public static ArithmeticOperation getSpecificOperation(String operation) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        return (ArithmeticOperation) resolveClass(operation).newInstance();
    }

    private static Class resolveClass(String className) throws ClassNotFoundException {
        return Class.forName(className);
    }
}