我相信了解Decorator和Visitor设计模式的意图。
虽然我可以列出以下差异
当我深入思考时,我无法说服自己两者之间的真正区别。
答案 0 :(得分:22)
嗯,实际上它们实际上是不同的!
当您想要使用一些新的,或多或少透明的功能(如验证或缓存)来增强现有对象时,可以使用 Decorator 。请参阅此处的示例:Should I extend ArrayList to add attributes that isn't null?
另一方面, 访问者在具有类的层次结构时使用,并且希望根据具体类型运行不同的方法,但避免使用instanceof
或typeof
运算符。请参阅现实生活中的示例:Is This Use of the "instanceof" Operator Considered Bad Design?
Decorator适用于一个对象,Visitor适用于复合结构,
访客适用于继承层次结构, Composite 是一种不同的GoF设计模式。
装饰者是结构设计模式,访客是行为设计模式。
是的,但它并没有真正帮助理解它们是如何工作的?
答案 1 :(得分:10)
设计模式并不意味着按实施差异进行分类,而是按何时使用其中一种进行分类。
它们用于完全不同的目的:
答案 2 :(得分:2)
我喜欢认为装饰器允许避免继承然后扩展类,因为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()
}
}
我为了空间而缩短了一些细节。例如,你可以抽出一个厨师来添加任何类型的顶部,然后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
}
}
答案 3 :(得分:1)
我解释它的方式,访问者代表我们可能想要采取或与对象相关的行为,但这不一定是对象所固有的,并且在关系中是相当水平的。例如,我可以为汽车“做一个营销宣传”,但我不会将汽车对象编程为具有“createMarketingPitch”功能,因为这对于在我的汽车对象上创建许多功能来说将是一个滑坡。
另一方面,装饰器是一种在现有对象之上对功能进行分层的模式,这是一种垂直关系,用于修改对象在调用其常规函数时的行为方式。此外,虽然访问者被编码为使用一类对象,但可以将装饰器分配给对象的特定实例,以便相同类型的不同实例的行为彼此不同。
答案 4 :(得分:1)
它们都“向现有对象添加功能”,而不修改原始类。区别在于:
使用装饰器您添加了包含此对象所具有的基本功能的功能(例如,除了执行某些基本操作外,还将其写入日志,此外还要将文件写入磁盘并对其进行加密) 。这也允许我们创建不同的装饰器组合,而无需对每个可能的场景进行子类化。
使用访问者您添加了一个全新的行为,您不希望将其定义为基本组件类本身的一部分(甚至不作为基本功能的包装),例如因为单个责任原则,公开原则等
当相同类型的不同子类之间的行为不同时(如果没有任何复杂的子类结构,但只有一个类,您可以创建一个新类并通过组合包含原始类并仍然实现目标)时,它尤其有用不影响或修改原始类)。这样,您可以避免使用if (a is ConcreteClass1) {...} else if (a is ConcreterClass2) {...}
之类的代码,而无需编写虚拟方法。
由于这种差异,使用装饰器,客户端代码调用在基本组件类的接口上定义的相同方法,它现在只是“装饰”了额外的功能,而对于访问者,客户端调用一些通用的“接受“方法并发送访问者。
答案 5 :(得分:0)
我想到装饰器模式的方式是我想在运行时向对象添加功能。通过将对象包装在可以扩展其方法的装饰器类中,我可以在程序运行时向对象添加行为。
对于访客模式我喜欢它,当我必须对“一组”相同类型的对象进行操作并收集信息时。让我说我有10个具体的蔬菜类别,我想知道所有10的总价格。我可以使用访客模式“访问”每个蔬菜对象,并在迭代结束时我有总价。当然,您也可以使用该模式将某些操作与对象分离。
答案 6 :(得分:0)
装饰器模式可用于静态地(或在某些情况下)在运行时扩展(装饰)某个对象的功能,独立于同一类的其他实例,提供一些基础在设计时完成
何时使用装饰器模式?
相关文章:
When to Use the Decorator Pattern?
访问者设计模式是一种将算法与其运行的对象结构分离的方法。这种分离的实际结果是能够在不修改这些结构的情况下向现有对象结构添加新操作。这是遵循开放/封闭原则的一种方式。
何时使用访客模式?
相关文章:
When should I use the Visitor Design Pattern?
有用的链接:
sourcemaking装饰文章
oodesign访问者文章
sourcemaking访问者文章
答案 7 :(得分:0)
是的,他们都在运行时向现有系统添加了一些功能,并试图降低对动态变化的反应(意义不大),但存在一些差异。
访问者主要是为了尊重OCP(有时是对SRP),以使系统更加灵活。您可以随着程序的发展添加任何访问者,而无需更改现有系统。但是,您需要以预先的方式设计系统。您无法为已经运行的系统添加新的访客类(或模式),并希望它无需重新编译,重新测试或无论如何都能正常工作。
另一方面,您可以使用Decorator通过在Decorator中包装抽象基类(您已经拥有)来丰富现有系统功能,并将您的丰富功能作为单独提供对象,这样你就可以根据需要创建。而且,从语义上讲,装饰者指的是某种东西的外观。
哪一个更喜欢?国际海事组织,回答这个可能会更有帮助。对我来说,我不喜欢装饰者使用基类的方式。它都使用继承和聚合。如果需要更改此(wrapee)类,最终会重新编译整个层次结构/模块。但它非常方便,您可以在设计时间之后更改行为。另一方面,在访客模式中,我不想了解访问者实现中的每个具体类型。添加新的基类类型时,还需要更改Visitor类以添加它。但是,如果您需要将代码注入现有系统而不改变结构,或者您需要在类中单独关注(单用户响应),那么它非常有用。
最后,是什么让访客比常规继承更好?要看。使用继承,您将更依赖于接口签名。使用Visitor使您的Visitor类依赖于具体类。更不用说使用访客添加更多行为而不更改现有模块签名,而不是在现有类中实现新接口。