Шаблон Java — посетителя для добавления методов

#java #design-patterns #visitor-pattern #open-closed-principle

#java #шаблоны проектирования #шаблон посетителя #принцип открытия-закрытия

Вопрос:

Итак, я создал простой шаблон посетителя для жидкостей. Таких как молоко, сок и ликер.

класс Milk может выглядеть следующим образом:

 public class Milk implements Visitable{

public float tax=0;

@Override
public int price() {
    return 4;
}

@Override
public void accept(Visitor visitor) {
    visitor.visit(this);
}
}
  

// и аналогично для сока и ликера

и тогда у нас может быть посетитель, который выглядит так, чтобы выполнять работу по расчету налогов :

 public class TaxVisitor implements Visitor {

double taxPerentLiquor=.18;
double taxPerentMilk=.15;
double taxPerentJuice=.10;


@Override
public void visit(Liquor liquor) {

    int price =liquor.price();
    liquor.setTax((float) (price*taxPerentLiquor));
}

@Override
public void visit(Milk milk) {
    float price =milk.price();
    milk.setTax((float) (price*taxPerentMilk));


}

@Override
public void visit(Juice juice) {

    int price =juice.price();
    juice.setTax((float) (price*taxPerentJuice));

}
  

}

и когда мы его используем, мы бы сделали это:

 Visitor taxVisitor = new TaxVisitor();

    Milk milk = new Milk();
    Juice juice = new Juice();

    milk.accept(taxVisitor);
    juice.accept(taxVisitor);
  

и «посетитель» рассчитал бы налог для каждой жидкости для меня. и я вижу преимущество в том, что мне не нужно изменять саму коллекцию объектов, когда я хочу добавить новое вычисление. Но моя проблема возникает, когда я хочу добавить новый метод. Следуя принципу open closed, я не должен добавлять новые методы в класс milk, например. Но давайте представим, что я хочу добавить функциональность, чтобы узнать, какого цвета жидкость. Итак, я хотел бы расширить объект milk, чтобы иметь метод с именем «getColor ()», который возвращал бы «#FFFFFF». Похоже, мне понадобится шаблон декоратора, чтобы добавить эту функциональность, если я хочу следовать принципу SOLID open closed. Есть ли способ сделать это с помощью шаблона посетителя?

Комментарии:

1. Если вы не планируете сохранять цвет каждой жидкости в посетителе (как вы сделали с tax), нет. Посетитель не добавляет поведение к объекту, он выполняет поведение для объекта. Как и в случае с вашим налоговым посетителем, вы не добавляете поведение к объектам, вы просто выполняете поведение, основанное на типе объекта (что может вызвать выполнение объектом уже существующего поведения)

2. Я понимаю. таким образом, посетитель предназначен для выполнения поведения, а не для добавления поведения.

3. Технически это добавляет поведение, но не к элементу. Поведение принадлежит семейству элементов, а не только одному. Проблема с применением этого к вашей ситуации выражается в вашем TaxVisitor : посетителю необходимо будет поддерживать любое состояние, не поддерживаемое элементами. Следовательно, если ни одна из жидкостей не сохраняла свой собственный цвет, a ColorVisitor должен был бы поддерживать их все. Это возможно, но непрактично.

4. Какой шаблон вы рекомендуете, если я хочу добавить методы (добавить поведение элемента) в свою коллекцию элементов без их изменения?

5. Добавление a getColor() к вашим жидкостям не нарушает O / C. В этом и заключается цель » открыть для расширения «: вы все равно можете добавлять поведение, если оно не влияет на какое-либо существующее поведение. Если вы повлияете на существующий код, также может быть затронут любой код, который зависит от него, что потенциально может нарушить контракты (тем самым нарушить программное обеспечение). Если добавление getColor() не влияет на какой-либо рабочий код, то это не нарушение принципа, а масштабирование. Посмотрите на первый пункт из этой ссылки

Ответ №1:

Добавьте функцию, вы не нарушаете O / C

Вы не нарушите O / C, добавив новую функцию, если эта функция не влияет на существующий код. Вы будете в порядке, добавляя a getColor() к своим жидкостям.

O / C предназначен для предотвращения модификации существующего кода

Цель O / C — избежать нарушений контракта. Когда разработчик пишет программное обеспечение, он точно определяет, как программное обеспечение должно и не должно работать. Это контракт.

При написании кода, от которого зависят другие разработчики, вы не можете быть уверены, какие контракты установили эти разработчики. Все, о чем вы знаете, это контракт, который вы определили для своего кода. Разработчики уверены, что вы не будете изменять свой контракт таким образом, который изменяет их.

Поскольку вы не можете быть уверены, повлияет ли изменение вашего контракта на контракты других разработчиков, любой ваш код, который используют другие разработчики, должен быть «ЗАКРЫТ для модификации«, иначе вы рискуете нарушить контракт.

O / C не мешает вам увеличивать масштаб

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

Если вы добавляете некоторые функции, никто не заставляет клиентов использовать эти новые функции в своих системах; им не нужно беспокоиться о каких-либо потенциальных рисках или о том, как они вообще работают, если они не будут использоваться. Классы «ОТКРЫТЫ для расширения«, так как это не причинит никакого потенциального вреда существующим клиентам.