装饰设计模式与继承?

use*_*625 24 c++ design-patterns

我已经阅读了维基百科的装饰设计模式,以及该网站的代码示例.

我认为传统继承遵循'is-a'模式,而decorator遵循'has-a'模式.装饰者的调用约定看起来像'皮肤'上的'皮肤'......超过'核心'.例如

I* anXYZ = new Z( new Y( new X( new A ) ) );
Run Code Online (Sandbox Code Playgroud)

如上面的代码示例链接所示.

但是仍然有一些我不明白的问题:

  1. wiki是什么意思'装饰模式可以用来在运行时扩展(装饰)某个对象的功能'?'new ...(new ...(new ...))'是一个运行时调用,但很好但是'AwithXYZ anXYZ;' 是编译时的继承而且不好?

  2. 从代码示例链接中我可以看到,两个实现中类定义数量几乎相同.我记得在其他一些设计模式书中,比如"Head first design patterns".他们使用starbuzz咖啡作为例子,并说传统的继承将导致"阶级爆炸",因为对于每种咖啡组合,你会想出一个类.

    但在这种情况下装饰者是不是一样的?如果一个装饰器类可以接受任何抽象类并进行装饰,那么我猜它确实可以防止爆炸,但是从代码示例中,你可以得到确切的类定义,不能少......

有人会解释吗?

Zde*_*vic 71

我们以一些抽象流为例,想象一下你想为它们提供加密和压缩服务.

使用装饰器(伪代码):

Stream plain = Stream();
Stream encrypted = EncryptedStream(Stream());
Stream zipped = ZippedStream(Stream());
Stream zippedEncrypted = ZippedStream(EncryptedStream(Stream());
Stream encryptedZipped = EncryptedStream(ZippedStream(Stream());
Run Code Online (Sandbox Code Playgroud)

有了继承,你有:

class Stream() {...}
class EncryptedStream() : Stream {...}
class ZippedStream() : Stream {...}
class ZippedEncryptedStream() : EncryptedStream {...}
class EncryptedZippedStream() : ZippedStream {...}
Run Code Online (Sandbox Code Playgroud)

1)使用装饰器,您可以根据需要在运行时组合功能.每个类只关注功能的一个方面(压缩,加密......)

2)在这个简单的例子中,我们有3个带有装饰器的类,5个带有继承的类.现在让我们添加一些服务,例如过滤和剪辑.使用装饰器,您只需要2个类来支持所有可能的场景,例如过滤 - >剪切 - >压缩 - >编码.通过继承,您需要为每个组合提供一个类,以便最终获得数十个类.

  • 谢谢Zdeslav.关于如何使用装饰器而不引起爆炸的一个很好的解释! (2认同)

Bet*_*eta 8

按相反顺序:

2)例如,有10个不同的独立扩展,在运行时可能需要任何组合,10个装饰器类将完成这项工作.要通过继承涵盖所有可能性,您需要1024个子类.并且没有办法解决大规模的代码冗余问题.

1)想象一下,你有1024个子类可以在运行时选择.尝试草拟出所需的代码.请记住,您可能无法决定选择或拒绝选项的顺序.还要记住,在扩展它之前,您可能需要使用一段时间.来吧,试试吧.相比之下,使用装饰器进行操作是微不足道的.