Избегайте статического связывания в операциях, которые используют аргументы иерархии
Я обнаружил проблему со статическим связыванием.
Мой реальный класс очень расширен, поэтому я буду использовать несколько игрушечных классов, чтобы выразить свою проблему.
Мы предполагаем, что имеем следующую иерархию.
public class Element{}
public class Element1 extends Element{}
public class Element2 extends Element{}
у меня естьStock
класс, который использует разныеElement
специализация определяетсяElement
иерархия.
public class Stock{
public void operation(Element1 e1){
System.out.println("Operation - " + e1.getClass().getName());
}
public void operation(Element2 e2){
System.out.println("Operation - " + e2.getClass().getName());
}
}
Наконец, у меня естьStockManager
который позволяет управлятьStock
.
public StockManager{
Stock stock;
public StockManager(Stock stock){
this.stock=stock;
}
public void manage(List<Element> elements){
for(Element element: elements){
stock.operation(element);
}
}
}
Конечно, этот код не компилируется, потому чтоStock
не определяет метод, который включает в себяElement
в качестве аргумента. В этом случае мы могли бы исправить код, используя разные подходы.
Во-первых, я смогу определить метод, который будет определятьElement
в качестве входного аргумента, например
public void operation(Element e){
System.out.println("Operation - " + e.getClass().getName());
}
Этот метод может определить переключатель для управления различными конкретными элементами (Element1
, Element2
). Тем не менее, это невозможно для меня, потому что переключатель нарушаютПринцип открытия / закрытияи у меня много (много) конкретных элементов.
Другой вариант, я мог бы использовать что-то вродеШаблон посетителя, Я мог бы отправитьStock
возражать против конкретного элемента. И конкретный элемент будет отвечать за использованиеStock
операции. Таким образом, класс может измениться на:
public abstract class Element{
public abstract void stockOperation(Stock stock);
}
public class Element1 extends Element{
public abstract void stockOperation(Stock stock){
stock.operation(this);
}
}
public class Element2 extends Element{
public abstract void stockOperation(Stock stock){
stock.operation(this);
}
}
ИStockManager
.
public StockManager{
Stock stock;
public StockManager(Stock stock){
this.stock=stock;
}
public void manage(List<Element> elements){
for(Element element: elements){
element.stockOperation(stock);
}
}
}
Это позволяет определить во время компиляции статический тип конкретных элементов. И динамическое связывание будет отвечать за вызовstockOperation
метод правильного конкретного элемента (Element1
или жеElement2
). ОДНАКО !!, у меня есть дублированный код в конкретных элементах, и у меня будет несколько конкретных элементов.
Итак, я хотел бы знать, знаем ли мы какой-либо дизайн шаблона или лучшую практику для решения этой проблемы. (Другая альтернатива, это может быть использование отражения, но я бы не хотел его использовать).