装饰设计模式与访客设计模式的区别

Til*_*lak 17 design-patterns decorator visitor

我相信了解Decorator和Visitor设计模式的意图.

虽然我可以列出以下差异

  1. Decorator在一个对象上工作,访问者在复合结构上工作,
  2. 装饰者是结构设计模式,访客是行为设计​​模式.

当我深入思考时,我无法说服自己两者之间的真正区别.

Tom*_*icz 23

嗯,他们实际上是不同的!

当您想要使用一些新的,或多或少透明的功能(如验证或缓存)来增强现有对象时,可以使用Decorator.请参阅此处的示例:我是否应该扩展ArrayList以添加非null的属性?

另一方面,如果您拥有类的层次结构并且希望根据具体类型运行不同的方法但是避免instanceof或typeof运算符,则使用访问者.请参阅现实生活中的示例:"instanceof"运算符的使用是否被视为错误设计?

Decorator在一个对象上工作,访问者在复合结构上工作,

访问者在继承层次结构上工作,Composite是一种不同的GoF设计模式.

装饰者是结构设计模式,访客是行为设计​​模式.

没错,但它并不能真正帮助理解它们的工作原理吗?

也可以看看


Jac*_*ack 10

设计模式并不意味着按实现差异进行分类,而是应该在何时使用其中一个或另一个进行分类.

它们用于完全不同的目的:

  • 当你想通过提供装饰其他对象的单个元素来动态丰富对象的功能时你会使用装饰器,这样他们确实会给它们添加一些行为(事实上它是一个结构模式,因为它改变了结构的结构你要跟的对象)
  • 当您想要将算法与其使用的对象分开时,您将使用访问者.你做的是你有这个访问者被传递给许多不同的对象,通常是一个层次结构(他们被称为接受访问者),这个访问者根据它在特定访问的对象的类型进行特定的操作.时刻.通过这种方式,您可以让访问者使用特定对象执行任何操作,而无需在对象本身中指定这些操作(这就是行为的原因).它是一种具有未在对象本身中定义的抽象方法.


Bor*_*ode 7

它们都向现有对象“添加功能”,而不修改原始类。区别在于:

使用装饰器,您可以添加包装此对象具有的基本功能的功能(例如,除了执行一些基本操作外,还将其写入日志,除了将文件写入磁盘还对其进行加密)。这也允许我们创建不同的装饰器组合,而无需对每个可能的场景进行子类化。

对于访问者,您添加了一个全新的行为,您不想将其定义为基本组件类本身的一部分(甚至不作为基本功能的包装器),例如因为单一职责原则、开放关闭原则等。尤其是当相同类型的不同子类之间的行为不同时很有用(如果没有任何复杂的子类结构而只有一个类,您可以创建一个新类并通过组合包含原始类,并且仍然实现不影响或修改原始类)。这样你就可以避免代码,就像if (a is ConcreteClass1) {...} else if (a is ConcreterClass2) {...}不编写虚拟方法一样。

由于这种差异,使用装饰器,客户端代码调用在基本组件类的接口上定义的相同方法,它现在只是“装饰”了额外的功能,而对于访问者,客户端调用一些通用的“接受”方法并将访客发送给它。


Swa*_*nil 5

我喜欢认为装饰器允许避免继承然后扩展类,就像 OOP 的一般原则一样,优先选择聚合而不是继承,尽管您确实以某种方式继承。这是一个过于简单的例子

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()
     } 
 }
Run Code Online (Sandbox Code Playgroud)

为了节省篇幅,我删减了一些细节。例如,您可以抽象出一个添加任何类型配料的厨师,然后 ChocoChef 就成为其具体类。现在,无论您准备什么,ChocoChef 总是会添加巧克力配料。现在,您可以通过将相应的 Chef 传递给其构造函数来获得巧克力饼干或巧克力蛋糕。另一方面,访问者对对象进行操作,并根据其正在访问的对象决定执行某些操作。

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
     }
}
Run Code Online (Sandbox Code Playgroud)


ari*_*ake 5

在我的解释中,访问者代表了我们可能想要对某个对象采取的操作,但这些操作不一定是对象固有的,并且在关系上是相当水平的。例如,我可以为一辆汽车“进行营销宣传”,但我不会对汽车对象进行编程以使其具有“createMarketingPitch”功能,因为这将导致在我的汽车对象上创建许多功能的滑坡。

另一方面,装饰器是一种将功能分层在现有对象之上的模式,这是一种垂直关系,可以修改对象在调用其正常函数时的行为方式。此外,虽然访问者被编码为处理一类对象,但装饰器可以分配给该对象的特定实例,以便同一类型的不同实例彼此表现不同。


归档时间:

查看次数:

9217 次

最近记录:

9 年 前