Использование шаблона посетителя - PullRequest
1 голос
/ 11 февраля 2012

https://stackoverflow.com/questions/9239445/sample-of-using-visitor-patternbefore-and-after

Правильно ли я понимаю основные цели шаблона посетителя?Как я понимаю:

До 1

public class Main {

    public static void main(String[] args) {
        List<CompanyItem> items = new ArrayList<CompanyItem>();
        items.add(new Employee(10));
        items.add(new Employee(10.6));
        items.add(new Employee(15.9));
        items.add(new Manager(20.1));
        items.add(new Boss(30));

        double totalSalary = 0;
        for(CompanyItem i:items){
            if (i instanceof Employee) {
                totalSalary += ((Employee) i).getSalary();
            } else if (i instanceof Manager) {
                totalSalary += ((Manager) i).getSalary();
                totalSalary += ((Manager) i).getBonusses();
            }else if (i instanceof Boss) {
                totalSalary += ((Boss) i).getSalary();
                totalSalary += ((Boss) i).getAdditionalSalary();
            }
        }
        System.out.println(totalSalary);
    }

    interface CompanyItem {
    }

    static class Employee implements CompanyItem {
        double salary;

        public Employee(double salary) {
            this.salary = salary;
        }

        public double getSalary() {
            return salary;
        }
    }

    static class Manager implements CompanyItem {
        double salary, bonusses;

        public Manager(double salary) {
            this.salary = salary;
            this.bonusses = 1.5 * salary;
        }

        public double getSalary() {
            return  salary;
        }

        public double getBonusses() {
            return bonusses;
        }
    }

    static class Boss implements CompanyItem {
        double salary, addSalary;

        public Boss(double salary) {
            this.salary = salary;
            this.addSalary = 3 * salary;
        }

        public double getSalary() {
            return salary;
        }

        public double getAdditionalSalary() {
            return addSalary;
        }
    }
}

До 2

public class Main3 {

    public static void main(String[] args) {
        List<CompanyItem> items = new ArrayList<CompanyItem>();
        items.add(new Employee(10));
        items.add(new Employee(10.6));
        items.add(new Employee(15.9));
        items.add(new Manager(20.1));
        items.add(new Boss(30));

        double totalSalary = 0;
        for(CompanyItem i:items){
            totalSalary+=i.getSalary();
            totalSalary+=i.getBonusses();
            totalSalary+=i.getAdditionalSalary();
        }
        System.out.println(totalSalary);
    }

    interface CompanyItem {
        public double getSalary();
        public double getBonusses();
        public double getAdditionalSalary();
    }

    static class Employee implements CompanyItem {
        double salary;

        public Employee(double salary) {
            this.salary = salary;
        }

        public double getSalary() {
            return salary;
        }

        @Override
        public double getBonusses() {
            return 0;
        }

        @Override
        public double getAdditionalSalary() {
            return 0;
        }
    }

    static class Manager implements CompanyItem {
        double salary, bonusses;

        public Manager(double salary) {
            this.salary = salary;
            this.bonusses = 1.5 * salary;
        }

        public double getSalary() {
            return  salary;
        }

        public double getBonusses() {
            return bonusses;
        }

        @Override
        public double getAdditionalSalary() {
            return 0;
        }
    }

    static class Boss implements CompanyItem {
        double salary, addSalary;

        public Boss(double salary) {
            this.salary = salary;
            this.addSalary = 3 * salary;
        }

        public double getSalary() {
            return salary;
        }

        public double getAdditionalSalary() {
            return addSalary;
        }

        @Override
        public double getBonusses() {
            return 0;
        }
    }
}

После (сиспользование шаблона посетителя ???)

public class Main1 {

    public static void main(String[] args) {
        List<CompanyItem> items = new ArrayList<CompanyItem>();
        items.add(new Employee(10));
        items.add(new Employee(10.6));
        items.add(new Employee(15.9));
        items.add(new Manager(20.1));
        items.add(new Boss(30));

        SalaryVisitor visitor = new SalaryVisitor();
        for(CompanyItem i:items){
            i.accept(visitor);
        }
        System.out.println(visitor.getTotalSalary());
    }

     interface CompanyItem {
        public void accept(Visitor v);
    }

    static class Employee implements CompanyItem {
        double salary;

        public Employee(double salary) {
            this.salary = salary;
        }

        public double getSalary() {
            return salary;
        }

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

    static class Manager implements CompanyItem {
        double salary,bonusses;

        public Manager(double salary) {
            this.salary = salary;
            this.bonusses = 1.5 * salary;
        }

        public double getSalary() {
            return  salary;
        }

        public double getBonusses(){
            return bonusses;
        }

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

    static class Boss implements CompanyItem {
        double salary, addSalary;

        public Boss(double salary) {
            this.salary = salary;
            this.addSalary = 3 * salary;
        }

        public double getSalary() {
            return  salary;
        }
        public double getAdditionalSalary(){
            return addSalary;
        }

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

    interface Visitor {
        public void visit(Employee e);
        public void visit(Manager m);
        public void visit(Boss b);
    }

    static class SalaryVisitor implements Visitor {
        double totalSalary;

        public SalaryVisitor() {
            totalSalary = 0;
        }

        public double getTotalSalary(){
            return totalSalary;
        }

        @Override
        public void visit(Employee e) {
            totalSalary += e.getSalary();           
        }

        @Override
        public void visit(Manager m) {
            totalSalary += (m.getSalary()+m.getBonusses()); 
        }

        @Override
        public void visit(Boss b) {
            totalSalary += (b.getSalary()+b.getAdditionalSalary()); 
        }
    }
}

Я прав?

Ответы [ 4 ]

8 голосов
/ 11 февраля 2012

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

Чтобы улучшить ваш пример, я предлагаю следующие изменения: Заменитьпростая система бонусов в системе, в которой фиксированный бонус (например, 100k $ в текущем году) распределяется между всеми менеджерами в соответствии с некоторыми бонусными баллами у каждого менеджера,Если есть два менеджера, один из которых имеет 140 баллов, другой 60 баллов, то первый получает 70 тыс. Долларов, второй - 30 тыс. Долларов.

Это позволяет вам иметь несколько посетителей:

  • Один для суммирования всех бонусных очков всех менеджеров
  • Один для распределения бонуса (100k $) между менеджерами, используя сумму из предыдущего шага.Установите этот рассчитанный индивидуальный бонус в поле в Manager
  • Третий посетитель (PaydayVisitor) распечатывает чеки для сотрудников, руководителей и менеджеров, а также возвращает сумму всех выполненных платежей.

РЕДАКТИРОВАТЬ В коде это будет выглядеть следующим образом (метод получения / установки пропущен только для краткости):

import java.util.ArrayList;
import java.util.List;

public class VisitorExample {
    public static void main(String[] args) {
        List<CompanyItem> items = new ArrayList<CompanyItem>();
        items.add(new Employee(10));
        items.add(new Employee(10.6));
        items.add(new Employee(15.9));
        items.add(new Manager(20.1, 140));
        items.add(new Manager(42.1, 70));
        items.add(new Boss(30, 10));

        // sum up all bonus points of all Managers
        BonusPointVisitor bonusPointVisitor = new BonusPointVisitor();
        for(CompanyItem i: items)
            i.accept(bonusPointVisitor);

        // distribute given bonus sum among the managers
        BonusDistributorVisitor bonusDistributorVisitor = 
            new BonusDistributorVisitor(bonusPointVisitor.totalBonusPoints, 100.0);
        for(CompanyItem i: items)
            i.accept(bonusDistributorVisitor);

        // PayDay - print all checks
        PrintCheckVisitor printCheckVisitor = new PrintCheckVisitor();
        for(CompanyItem i: items)
            i.accept(printCheckVisitor);
        System.out.println("total money spent this month: "+printCheckVisitor.totalPayments);
    }

    interface CompanyItem {
        public void accept(Visitor v);
    }

    interface Visitor {
        public void visit(Employee e);
        public void visit(Manager m);
        public void visit(Boss b);
    }

    static class Employee implements CompanyItem {
        double salary;

        public Employee(double salary) {
            this.salary = salary;
        }

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

    static class Manager implements CompanyItem {
        double salary, bonusPoints, bonus;

        public Manager(double salary, double bonusPoints) {
            this.salary = salary;
            this.bonusPoints = bonusPoints;
            this.bonus = 0;
        }

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

    static class Boss implements CompanyItem {
        double salary, addSalary;

        public Boss(double salary, double addSalary) {
            this.salary = salary;
            this.addSalary = addSalary;
        }

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

    static class BonusPointVisitor implements Visitor {
        double totalBonusPoints = 0d;

        @Override
        public void visit(Employee e) {
        }

        @Override
        public void visit(Manager m) {
            totalBonusPoints += m.bonusPoints;
        }

        @Override
        public void visit(Boss b) {
        }
    }


    static class BonusDistributorVisitor  implements Visitor {
        double totalBonusPoints, totalBonus;

        public BonusDistributorVisitor(double totalBonusPoints, double totalBonus) {
            this.totalBonusPoints = totalBonusPoints;
            this.totalBonus = totalBonus;
        }

        @Override
        public void visit(Employee e) {
        }

        @Override
        public void visit(Manager m) {
            m.bonus = (m.bonusPoints / totalBonusPoints) * totalBonus;
        }

        @Override
        public void visit(Boss b) {
        }
    }

    static class PrintCheckVisitor implements Visitor {
        double totalPayments = 0;

        @Override
        public void visit(Employee e) {
            advisePayment(e.salary);
        }

        @Override
        public void visit(Manager m) {
            advisePayment(m.salary + m.bonus);
        }

        @Override
        public void visit(Boss b) {
            advisePayment(b.salary + b.addSalary);
        }

        private void advisePayment(double amount){
            System.out.println("pay "+amount+" credits");
            totalPayments += amount;
        }
    }
}

Что еще предстоит сделать: дать каждому элементу возможность печатиимя для использования в advisePayment.

1 голос
/ 11 февраля 2012

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

1 голос
/ 11 февраля 2012

Зависит от того, будут ли у вас другие посетители, кроме SalaryVisitor. Если у вас нет других посетителей, вам следует избегать шаблона посетителей: это очень «тяжелый» шаблон, и он здесь не кажется необходимым.

EDIT
Первоначально я сказал, что предпочитаю До 2 , но, следуя комментарию AH, возможно, вы могли бы создать новый подкласс под названием PaidByCompany (плохое имя, но сейчас я не мог придумать ничего хорошего), который имеет метод getTotalCompensation (). До 1 тоже работает нормально как есть.

1 голос
/ 11 февраля 2012

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

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