如何在Java中实现静态可扩展注册表

时间:2019-06-07 23:29:54

标签: java design-patterns

我正在尝试实现一个静态注册表,该扩展可由第三方开发人员再次将其项添加到此注册表中来扩展。

我遇到了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;
    }
}

2 个答案:

答案 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)); 
}