装饰者模式与子类化

时间:2011-01-30 12:52:27

标签: design-patterns decorator

我可以通过添加子类来解决添加功能的问题那么为什么我应该使用装饰模式什么是装饰模式的真正优势呢?

6 个答案:

答案 0 :(得分:44)

GoF的一个例子:

  

假设您有一个TextView类。然后在某些地方你需要一个滚动的文本视图,所以你继承TextView并创建ScrolledTextView类。在其他一些地方你想要一个文本视图边框。所以你再次创建子类并创建BorderedTextView。好吧,现在在某个地方你想要边框和滚动两者。前两个子类中没有一个具有这两种能力。所以你需要创建第三个。创建ScrolledBorderedTextView时,实际上是在复制工作量。如果您有任何方法可以构成前两个的功能,则不需要此类。嗯,事情可能会变得更糟,这可能导致不必要的阶级爆炸。

基本上,通过使用装饰器模式,您可以在RUN TIME向对象添加任意数量的附加责任,这是通过子类化无法实现的,而不会对代码结构造成损害。

但有一点,设计模式不是你必须使用的东西。是否需要模式取决于您的特定问题,您希望长时间维护代码,是否要扩展代码以及许多其他因素。并且没有任何模式在所有情况下都有用。适合某种情况的模式(装饰者或任何其他)可能不是另一种情况的好选择。

答案 1 :(得分:38)

来自Decorator pattern at wikipedia

  

可以使用装饰器模式   使扩展(装饰)成为可能   某个对象的功能   在运行时

装饰器模式的重点是动态添加其他行为/功能,这在设计时当然是不可能的。

来自同一篇文章:

  

装饰者模式是一个   子类化的替代方案。   子类化在编译时添加行为   时间,这种变化会影响所有人   原始类的实例;   装饰可以提供新的行为   单个对象的运行时

答案 2 :(得分:18)

GoF Design Patterns book确定了使用装饰器而不是子类化的两个主要优点:

  
      
  1. 比静态更灵活   继承。装饰者模式   提供了一种更灵活的添加方式   对象的责任比可以   与静态(多个)   遗产。有装饰,   责任可以添加和   仅在运行时删除   连接和拆卸它们。在   相比之下,继承需要   为每个人创建一个新类   额外责任(例如,   BorderedScrollableTextView,   BorderedTextView)。这引起了兴趣   到很多班级并且增加了   系统的复杂性。此外,   提供不同的装饰   特定组件的类   class让你混合搭配   责任。

         

    装饰器也可以轻松添加   一个属性两次。例如,到   给TextView一个双边框,   只需附加两个BorderDecorators。   从Border类继承两次   最多容易出错。

  2.   
  3. 避免使用功能丰富的课程   在层次结构中。装饰者提供了一个   按需付费即可添加   责任。而不是尝试   支持所有可预见的功能   在一个复杂的,可定制的类中,   你可以定义一个简单的类和   逐步添加功能   装饰者对象。功能可以   由简单的作品组成。作为一个   结果,申请无需支付   对于它不使用的功能。它的   也容易定义新的种类   装饰者独立于   他们扩展的对象类,甚至   对于不可预见的扩展。扩展   一个复杂的类往往暴露   与...无关的细节   你要添加的职责。

  4.   

从我的观点来看,单独防止子类爆炸非常引人注目。

如果你想要TextWindow添加水平滚动,垂直滚动和边框,所有这些都是独立的,也可以选择使用子类,你必须为HorizontalScrollingTextWindow定义子类,{{ 1}},VerticalScrollingTextWindowHorizontalAndVerticalScrollingTextWindowBorderedTextWindowHorizontalScrollingBorderedTextWindowVerticalScrollingBorderedTextWindow等等,如果您关心滚动和边界的顺序。

使用装饰器,您只需要定义两个滚动装饰器和一个边框装饰器。

答案 3 :(得分:11)

子类化可能会导致Liskov substitution principle出现问题。装饰者避免了这一点。

装饰器的另一个优点是你正在编写(强制写入)接口。这使得测试更容易。确实,您的对象层次结构也可以写入接口,因此具有一些相同的优点,但是,我可以单独测试装饰器类的单个实现。我不能对子类做同样的事情,因为我总是将整个层次结构返回到基类。我无法单独测试新代码。

使用装饰器模式并遵循单一责任原则,我可以创建几个装饰器并按我希望的方式堆叠它们。我可以在运行时配置它。在继承中,我要么必须创建每个可能的分支(a-> b-> c然后a-> c-> b,从而复制代码并爆炸测试次数),或者我创建1个层次结构然后添加另一个在需要时,但这会触发新的测试/发布周期。

这就是你想要使用装饰器模式而不是子类化的原因。

答案 4 :(得分:2)

以下是基于实际实施的差异。

装饰是子类化的另一种方式,可以扩展现有类的功能。这是我们应该使用子类或装饰器的一些场景。

1)子类主要用于扩展类似功能的情况    想要保留旧功能和新功能的一组类    在子类中    并且子类的所有实例共享相同的功能。要是我们    更改子类,然后它将反映所有的实例    儿童班。如    层次关系船,类似的一组。

父 - >儿童安全>孙子

Car-> Maruti 800-> Maruti 100(将具有Maruti 800和New的功能)

2)装饰器模式用于装饰现有的类而不改变旧的行为。例如类圆有平滑边框,但我们需要用红色边框装饰它,一段时间后一些用户想要黄色圆圈和一些用户想要带有绿色边框的圆圈,有些用户想要红色和黄色边框圈,有些用户想要红色和绿色边框圈等,为此它是完美的图案,因为它会减少组合类别。下面就是例子。

Icircle cir =新的RedDecorator(新圆圈())用红色装饰圆圈

Icircle cir = new YellowDecorator(new circle())用黄色装饰圆圈

Icircle cir =新的RedDecorator(新的YellowDecorator(新圆圈()))装饰

用红色和黄色圈,这里我们不需要创建RedAndYellow类装饰器。同样地,我们可以用其他组合装饰圆圈而不创建新的组合类。

通过这种方式,它减少了组合类的数量。

以下是装饰器模式的有用链接

https://www.tutorialspoint.com/design_pattern/decorator_pattern.htm

答案 5 :(得分:1)

灵活性,这就是IMO的原因。