Почему посетитель ответственен за перечисление детей в шаблоне "посетитель"?

Думаю, из конфига вы пытаетесь опубликовать то же сообщение еще раз в том же месте назначения dest_1.

spring.cloud.stream.bindings.input1.destination=dest_1
spring.cloud.stream.bindings.output1.destination=dest_1

И из журнала ясно, что второе сообщение имеет другой идентификатор

id=788e8bbf-4ae4-86cc-0859-d4f153cb5807
id=2f22ce16-bb5a-350c-8b3d-e6c898760888
7
задан BCS 7 February 2009 в 00:42
поделиться

4 ответа

Объект посетителя требуется, чтобы знать структуру вещей, которые это посещает. Это в порядке, все же. Вы, как предполагается, пишете специализированные операции посещения для каждого типа вещи, которую знает посетитель, как посетить. Это позволяет посетителю решать, сколько это действительно хочет посетить, и в какой порядок.

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

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

Если Вы хотите перенести простую операцию и позволить набору дать Вам каждый объект для действия на, то Вы хотите, чтобы набор обеспечил итератор для себя. Вызовите свою функцию на каждой вещи, которую итератор дает Вам.

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

13
ответ дан 6 December 2019 в 09:23
поделиться

Да. Посещаемые объекты могут сделать перечисление (т.е. обратиться к необходимым детям). Это все еще называют шаблоном "Посетителя" (на самом деле, первая выборка Шаблона разработки Посетителя делает это этот путь). Мой искусственный отрывок в качестве примера:

public void accept(Visitor visitor) {
  for (Node n : children) {
    n.accept(visitor);
  }
}

Примечание: для посещения детей мы не можем сказать visitor.visit(n);. Это вызвано тем, что Java динамично не выбирает метод (на основе класса среды выполнения его аргументов), но выбирает метод статически (типом времени компиляции его аргументов).

3
ответ дан 6 December 2019 в 09:23
поделиться

Взгляните на объяснение в этой статье.

От Wiki:

В объектно-ориентированном программировании и разработке программного обеспечения, шаблон разработки посетителя является способом разделить алгоритм от структуры объекта, на которую это работает. Практическим результатом этого разделения является способность добавить новые операции к существующим структурам объекта, не изменяя те структуры. Таким образом использование шаблона "посетитель" помогает соответствию с открываться/закрывать принципом.

0
ответ дан 6 December 2019 в 09:23
поделиться

В коротких словах я думаю, что Шаблон "посетитель" является ортогональным к способу, которым сделано перечисление. Это может быть сделано так или иначе, или никакое перечисление вообще.

Я думаю, что посетитель обязан знать то, из чего состоит посещаемая структура элементов. Любите знать, что автомобиль состоит из Колес и Механизма. Знать, как точно они объединены, не необходимо, я думаю. Рассмотрите следующий пример. Инсайдер знает посещаемую структуру объекта и выполняет само перечисление. Посторонний не знает это и делегирует перечисление к посещаемому объекту.

interface Visitable {
    void accept(Visitor visitor);
}

class WorkingRoom implements Visitable {
    public int number;
    WorkingRoom(int number) {
        this.number = number;
    }

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

class BossRoom implements Visitable {
    public String bossName;
    BossRoom(String bossName) {
        this.bossName = bossName;
    }
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

interface Visitor{
    void visit(WorkingRoom workingRoom);
    void visit(BossRoom bossRoom);
    void visit(Office office);
}

class Office implements Visitable{
    public Visitable[] firstFloor;
    public Visitable[] secondFloor;
    public Visitable ceoRoom;
    public Office(){
        firstFloor = new Visitable[]{ new WorkingRoom(101),
                                        new WorkingRoom(102),
                                        new BossRoom("Jeff Atwood"),
                                        new WorkingRoom(103)};
        secondFloor = new Visitable[]{  new WorkingRoom(201),
                                        new WorkingRoom(202),
                                        new BossRoom("Joel Spolsky")};

        ceoRoom = new BossRoom("Bill Gates");
    }

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

    public void showMeTheOffice(Visitor visitor, boolean sayPlease) {
        // Office manager decides the order in which rooms are visited
        for(int i=secondFloor.length-1; i >= 0; i--){
            secondFloor[i].accept(visitor);
        }
        if (sayPlease){
            ceoRoom.accept(visitor);
        }
        for (int i = 0; i < firstFloor.length; i++) {
            firstFloor[i].accept(visitor);
        }
    }
}

class Insider implements Visitor{
    public void visit(WorkingRoom workingRoom) {
        System.out.println("I> This is working room #"+workingRoom.number);
    }

    public void visit(BossRoom bossRoom) {
        System.out.println("I> Hi, "+bossRoom.bossName);
    }

    public void visit(Office office) {
        // I know about office structure, so I'll just go to the 1st floor
        for(int i=0;i<office.firstFloor.length;i++){
            office.firstFloor[i].accept(this);
        }
    }
}

class Outsider implements Visitor{

    public void visit(Office office) {
        // I do not know about office structure, but I know they have a 
        // nice office manager
        // I'll just ask to show me the office
        office.showMeTheOffice(this, true);
    }

    public void visit(WorkingRoom workingRoom) {
        System.out.println("O> Wow, room #"+workingRoom.number);
    }

    public void visit(BossRoom bossRoom) {
        System.out.println("O> Oh, look, this is "+bossRoom.bossName);
    }
}

public class Main{
    public static void main(String[] args) {
        Office office = new Office(); // visited structure
        // visitor who knows about office structure
        Insider employee = new Insider(); 
        office.accept(employee);
        System.out.println();
        // visitor who does not know about exact office structure
        // but knows something else
        Outsider candidate = new Outsider(); 
        office.accept(candidate);

        // no enumeration at all, but still a visitor pattern
        Visitable v = new BossRoom("Linus Torvalds");
        v.accept(candidate);
    }
}

У меня был проект с широким использованием шаблона "посетитель" без любого перечисления вообще. У нас были основной интерфейс Field и много классов, реализовывая его, как StringField, NumberField, и т.д. Очень часто мы должны были сделать разные вещи на основе типа поля, например, представить его по-другому, загрузка из DB, экспорта в xml, и т.д. Мы могли определить методы в интерфейсе Field, но это сделает его вместе с каждой функцией проекта - плохое поле должно знать об экспорте, импорте, рендеринге к HTML и rtf, и т.д. Мы также могли использовать instanceof, но набор возможных классов, реализовывая интерфейс Field изменялся со временем, и было возможно добавить новый тип поля и забыть добавлять

else if (field instanceof NewlyAddedFieldType) {...}

где-нибудь. Таким образом, мы решили использовать шаблон "посетитель", и он был похож

Visitor v = new XMLExportVisitor(outputStream);
field.accept(v);

Поскольку любая Полевая реализация требуется, чтобы иметь метод

void accept(FieldVisitor visitor)

затем, если я добавляю новую реализацию интерфейса Field, я должен реализовать его так или иначе. Обычно это

visitor.visit(this);

где это - недавно добавленный класс. Это вынуждает меня добавить

void visit(NewlyAddedClass visited);

к интерфейсу FieldVisitor, который заставляет меня реализовать его в каждой реализации FieldVisitor, которую мы уже имеем. Таким образом, если я забуду делать что-то вроде этого то - я получу ошибку компилятора. Перечисление в этом случае, если таковые имеются, было сделано за пределами посещаемой структуры и посетителя. Но я все еще думаю об этом как допустимый случай шаблона "посетитель". Это, оказалось, было немного более твердо реализовать, но легче и более безопасный использовать.

2
ответ дан 6 December 2019 в 09:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: