Избегайте статического связывания в операциях, которые используют аргументы иерархии

Я обнаружил проблему со статическим связыванием.

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

Мы предполагаем, что имеем следующую иерархию.

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). ОДНАКО !!, у меня есть дублированный код в конкретных элементах, и у меня будет несколько конкретных элементов.

Итак, я хотел бы знать, знаем ли мы какой-либо дизайн шаблона или лучшую практику для решения этой проблемы. (Другая альтернатива, это может быть использование отражения, но я бы не хотел его использовать).

Ответы на вопрос(1)

Ваш ответ на вопрос