Как реализовать статический расширяемый реестр в Java - PullRequest
0 голосов
/ 08 июня 2019

Я пытался реализовать статический реестр, который сторонние разработчики могли бы расширить, добавляя свои элементы в этот реестр, опять же, статически.

Я столкнулся с проблемой, описанной в Java: использованиеСтатический инициализатор блокирует регистрацию классов в глобальном статическом реестре - однако описанное там предложение иметь Регистратор , который регистрирует каждый класс, не соответствует моим требованиям, так как сторонние разработчики в моем случае получают только моибиблиотеку в банке, и они могут только расширять ее, добавляя в нее дополнительные классы, но ничего не меняя в моей банке.

Есть предложения для достижения этого, если вообще возможно?(должно быть, я предполагаю)

вот что у меня есть:

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 голосов
/ 09 июня 2019

Вам не нужны статические инициализаторы.Зарегистрируйте сторонних операторов перед использованием 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)); 
} 
0 голосов
/ 08 июня 2019

Если я правильно понимаю ваш вопрос, вам нужен динамический шаблон 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

Должен быть метод load, который будет загружаться каждый разнезависимо от того, является ли новый символ или нет.Я предлагаю сохранить другой файл XML или свойства, который будет иметь реализацию символа и класса OperatorService.Если вы распространяете свой 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);
    }

Надеюсь, что это может быть полезно, другие старшие члены могут пролить больше света на этот дизайн.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...