Разница между шаблоном дизайна декоратора и шаблоном дизайна посетителя - PullRequest
17 голосов
/ 20 февраля 2012

Я верю, чтобы понять намерения шаблона проектирования Decorator и Visitor.

Хотя я могу перечислить следующие различия

  1. Декоратор работает на объекте, Посетитель работает на составной структуре,
  2. Декоратор - это шаблон Структурного проектирования, посетитель - шаблон Поведенческого дизайна.

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

Ответы [ 8 ]

22 голосов
/ 20 февраля 2012

Ну, на самом деле они настолько разные, насколько могут быть!

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

Посетитель , с другой стороны, используется, когда у вас есть иерархия классов и вы хотите запустить другой метод, основанный на конкретном типе, но избегая операторов instanceof или typeof. См. Реальный пример: Это использование оператора instanceof считается плохим дизайном?

Декоратор работает на объекте, посетитель работает на составной структуре,

Посетитель работает в иерархии наследования, Составной - это другой шаблон проектирования GoF.

Декоратор - Структурный шаблон дизайна, посетитель - Поведенческий шаблон дизайна.

Правда, но на самом деле это не помогает понять, как они работают?

Смотри также

10 голосов
/ 20 февраля 2012

Шаблоны проектирования предназначены не для классификации по различиям реализации, а по тому, когда вам следует использовать тот или иной.

Они служат для совершенно разных целей:

  • вы будете использовать декоратор, когда хотите динамически обогащать функциональность объектов, предоставляя отдельные элементы, которые украшают другие объекты, так что они действительно добавляют к ним некоторое поведение (на самом деле это структурный * шаблон 1009 * в том смысле, что он изменяет структуру объектов, с которыми вы просыпаетесь)
  • вы будете использовать посетителя, когда захотите отделить алгоритм от объектов, с которыми он работает. То, что вы делаете, это то, что у вас есть этот посетитель, который передается множеству различных объектов, обычно иерархии (они, как говорят, принимают посетителя), этот посетитель выполняет определенные операции в соответствии с типом объектов это посещение в определенный момент. Таким образом, вы можете заставить своего посетителя делать с конкретными объектами все, что ему нужно, без необходимости указывать эти операции в самих объектах (вот почему это поведенческий ). Это своего рода наличие абстрактных методов, которые не определены в самом объекте.
2 голосов
/ 20 февраля 2012

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

abstract class Chef{
  public abstract void Prepare();
}

class CookieMaker:Chef{         //Concrete class
   public override void Prepare()
    {
        //Bake in Oven
     }
 }

  // Decorator class
 // This chef adds chocolate topping to everything
 class ChocoChef:Chef{  

     public ChocoChef(Chef mychef)
     {
        this.chef = mychef; 
     }

     public override void Prepare()
     {
           // Add chocolate topping first
           chef.Prepare()
     } 
 }

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

class Student{
     // Different visitors visit each student object using this method
     // like prize distributor or uniform inspector
     public Accept(IVisitor v)
     {
         v.Visit(this)
     }
}

 // Visitor visits all student OBJECTS
class PrizeDistributor:IVisitor{
     public override void Visit(Student s)
     {
           //  if(s has scored 100)
           // Award prize to s
     }
}
1 голос
/ 16 сентября 2016

Они оба «добавляют функциональность» к существующему объекту без изменения исходного класса.Разница в следующем:

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

С посетителем Вы добавляете совершенно новое поведение, которое не хотите определять как часть самого базового класса компонентов (даже не как обертку для основных функций), например, потому чтопринципа единой ответственности, принципа открытого закрытия и т. д. Это особенно полезно, когда это поведение будет различным в разных подклассах одного типа (если не существует сложной структуры подклассов, а есть только один класс, вы можете просто создать новый класс и включитьисходный класс с помощью композиции и по-прежнему достигать цели не затрагивать или изменять исходный класс).Таким образом, вы можете избежать кода типа if (a is ConcreteClass1) {...} else if (a is ConcreterClass2) {...} без написания виртуальных методов.

В результате этого различия, с помощью декоратора, клиентский код вызывает тот же метод, который определен в интерфейсе базового класса компонентов, этотеперь просто «украшен» дополнительной функциональностью, в то время как с посетителем клиент вызывает какой-то общий метод «принять» и отправляет посетителя на него.

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

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

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

0 голосов
/ 01 ноября 2016

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

Посетитель в первую очередь должен уважатьOCP (а иногда и SRP), чтобы сделать систему более гибкой.Вы можете добавить любого посетителя, которого сможете, по мере развития вашей программы без изменения существующей системы.Однако вам необходимо заранее спроектировать систему .Вы не можете добавить новый класс (или шаблон) посетителя к уже работающей системе и ожидать, что он будет работать без перекомпиляции, повторного тестирования или чего-либо еще.

С другой стороны, вы можете использовать Decorator для обогащения функциональность существующей системы , оборачивая абстрактный базовый класс (который у вас уже есть) в Decorator и предоставляя вашу расширенную функцию в качестве отдельного объекта, чтобы вы могли создавать ее по мере необходимости.Более того, семантически Decorator скорее относится к внешнему виду sth.

Какой из них предпочтительнее?ИМО, ответ на этот вопрос может быть более полезным.Мне не нравится, как декоратор использует базовый класс.Он использует наследование и агрегацию.Если вам нужно изменить этот класс (wrapee), вам придется перекомпилировать всю иерархию / модуль.Но с тех пор это удобно, и вы можете изменить поведение после время разработки .С другой стороны, в шаблоне Visitor мне не нравится идея знать каждый конкретный тип в реализации Visitor.Когда вы добавляете новый тип базового класса, вам также нужно перейти и изменить класс Visitor, чтобы добавить его.Но это полезно, когда вам нужно внедрить код в существующую систему без изменения структуры или если вам нужно разделить задачи в классе (Single-User Resp).

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

0 голосов
/ 23 сентября 2016

Декоратор

Шаблон Декоратор может использоваться для расширения (декорирования) функциональности определенного объекта статически или в некоторых случаях во время выполнения,независимо от других экземпляров того же класса, при условии, что во время проектирования сделаны некоторые фундаментальные работы

Когда использовать шаблон Decorator?

  1. Обязанности и поведение объекта должны динамически добавляться / удаляться
  2. Конкретные реализации должны быть отделены от обязанностей и поведения
  3. Когда подклассы слишком дороги для динамического добавления / удаления обязанностей

Похожие сообщения:

Когда использовать шаблон декоратора?

Посетитель :

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

Когда использовать шаблон посетителя?

  1. Аналогичные операции должны бытьвыполняется на объектах разных типов, сгруппированных в структуру
  2. Вам необходимо выполнить множество различных и не связанных операций.Он отделяет операцию от объектов. Структура
  3. Новые операции должны добавляться без изменения структуры объекта
  4. Собирать связанные операции в один класс, а не заставлять вас изменять или получать классы
  5. Добавление функций в библиотеки классов, для которых у вас либо нет источника, либо вы не можете изменить источник

Связанный пост:

Когда мне следует использовать шаблон проектирования посетителя?

Полезные ссылки:

создание исходного кода статья декоратора

oodesign статья посетителя

sourcemaking посетитель статьи

0 голосов
/ 21 сентября 2016

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

Для шаблона посетителя мне нравится, когда мне нужно выполнить операцию над «набором» объектов одного типа и собрать информацию.Допустим, у меня есть 10 конкретных классов овощей, и я хочу знать общую цену на все 10. Я могу использовать шаблон посетителей, чтобы «посетить» каждый овощной объект, и в конце итерации у меня будет общая цена.Конечно, вы также можете использовать шаблон как способ отделить некоторые операции от объекта (ов).

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