我正在尝试实现一个静态注册表,该扩展可由第三方开发人员再次将其项添加到此注册表中来扩展。
我遇到了Java: use static initializer blocks to register classes to global static registry中描述的问题-但是,那里描述的建议是注册一个 Registrar 来注册每个课程,这不符合我的要求,因为我的第三方开发人员情况下只能将我的库放在jar中,他们只能扩展它,向其中添加其他类,而不能修改jar中的任何内容。
是否有实现此目标的建议? (应该是,我猜是这样)
这是我拥有的:
import java.util.HashMap;
public class Calculator {
public double eval(String symbol, double operand1, double operand2) {
return OperatorRegistry.get(symbol).calculate(operand1, operand2);
}
public static void main(String[] args) {
Calculator c = new Calculator();
System.out.println(c.eval("+", 3, 9));
System.out.println(c.eval("-", 13, 9));
}
}
class OperatorRegistry {
static HashMap<String, Operator> registry = new HashMap<String, Operator>();
public static void register(Operator o) {
System.out.println("Registering: " + o.getSymbol());
registry.put(o.getSymbol(), o);
}
public static Operator get(String c) {
return registry.get(c);
}
}
interface Operator {
public String getSymbol() ;
public double calculate(double a, double b) ;
}
class AddOperator implements Operator{
static {
OperatorRegistry.register(new AddOperator());
}
public String getSymbol() {
return "+";
}
public double calculate(double a, double b) {
return a + b;
}
}
class SubtractOperator implements Operator {
static {
OperatorRegistry.register(new SubtractOperator());
}
public String getSymbol() {
return "-";
}
public double calculate(double a, double b) {
return a - b;
}
}
答案 0 :(得分:0)
如果我正确理解了您的问题,则需要一个动态的Service Locator模式,即使在运行时也要在需要时按需执行。这意味着,如果有一个新符号,并且有一个用于操作员的实现,则它应该起作用。我在告诉您以下代码的底线。
public double eval(String symbol, double operand1, double operand2) {
return OperatorRegistry.get(symbol).calculate(operand1, operand2);
}
我的建议是维护一张这样的地图。
Map<String (Symbol), OperatorService(Operator Impl)> symbolOpServiceMap
必须有一个加载方法,无论是否有新符号,每次都会加载。我建议维护另一个具有符号和OperatorService类实现的xml或属性文件。如果分发jar,则将jar与外部化的xml,json或属性文件一起分发,以便所有操作员服务都将在运行时加载。这意味着,您将提供灵活性,使静态和动态服务都将始终加载,并且您应该能够执行以下代码。
OperatorRegistry.get(symbol).calculate(operand1, operand2);
要使其更整洁,应具有以下结构。
public double eval(String symbol, double operand1, double operand2) {
loadAllOperatorServices();// <= This method will always be invoked and it //will read from xml, json file based upon the number of entries for symbol and //its corresponding implementation.
return OperatorRegistry.get(symbol).calculate(operand1, operand2);
}
希望这可能有用,其他高级成员可以对此设计给予更多的了解。
答案 1 :(得分:0)
您不需要静态初始化程序。在使用Calculator
之前注册第三方运营商:
// Code of 3rd party developer:
public static void main(String[] args) {
OperatorRegistry.register(new MultiplyOperator());
OperatorRegistry.register(new PowerOperator());
Calculator c = new Calculator();
System.out.println(c.eval("+", 3, 9));
System.out.println(c.eval("-", 13, 9));
System.out.println(c.eval("*", 3, 9));
System.out.println(c.eval("^", 13, 9));
}
并让计算器本身注册默认运算符。
也许将静态OperatorRegistry.register(Operator)
移到Calculator
会更方便:
Calculator.registerOperator(Operator);
然后Calculator
将变为:
public class Calculator {
private static OperatorRegistry operatorRegistry = new OperatorRegistry();
// Register default operators
static {
Calculator.operatorRegistry.register(new SubtractOperator());
Calculator.operatorRegistry.register(new AddOperator());
}
public static registerOperator(Operator operator) {
// Delegate call to 'OperatorRegistry'
Calculator.operatorRegistry.register(operator);
}
public double eval(String symbol, double operand1, double operand2) {
return Calculator.operatorRegistry.get(symbol).calculate(operand1, operand2);
}
}
// Code of 3rd party developer:
public static void main(String[] args) {
Calculator.registerOperator(new MultiplyOperator());
Calculator.registerOperator(new PowerOperator());
Calculator c = new Calculator();
System.out.println(c.eval("+", 3, 9));
System.out.println(c.eval("-", 13, 9));
System.out.println(c.eval("*", 3, 9));
System.out.println(c.eval("^", 13, 9));
}