你的问题对我来说似乎有点循环......实现一个接口并拥有一个“装饰”的接口实例是装饰器模式的定义。
所以你的问题有点像问“为什么装饰器模式使用装饰器模式?”
如果你要包装的东西和你自己之间没有共同的接口,它只是一种有关系,或者,如果你正在调整你要包装的东西的接口到其他接口,可能是适配器模式。
我认为您真正的问题是“为什么装饰器模式有用?是什么让实现与您包装的东西相同的接口有用?”
装饰器模式支持同一行为的变化
装饰器模式的最大价值在于,当您有一些系统必须处理几个细微不同的事情,但又不想知道复杂性,并且能够以相同的方式对待它们时。当然,这通常是我们从接口中得到的。但在某些情况下,同一接口的大量实现并不是最佳解决方案……在经典示例中,假设您尝试为星巴克提供的每种咖啡编写一个单独的类。
您将从基础开始,但逐渐发现自己需要编写像VentiMochaChaiWhipWithCinnamonOnTop 这样的类。每次添加一种新的风味成分,你就需要编写几十个新类,每次删除一个,就会有几十个类被淘汰。
另一方面,通过装饰器模式,您可以为每种饮料设置一个单独的类,并使大部分软件系统不必处理各种饮品种类;他们可以通过Drink 界面对每种饮料一视同仁(无论它有多少附加组件)。
当结帐的人点击 Chai 按钮时,您只需创建一个 new Chai(),因为其他属性可以添加到任意饮料中,您只需将其包装为 new Venti(drink)、new Mocha(drink)、new Whip(drink) 、new WithCinnamon(drink) 等,因为客户请求附加组件并且收银员点击按钮。
装饰器模式的局限性
该模式有其局限性,因为与仅对每种调味品使用一组布尔值相比,对您所喝的确切饮料进行自省要困难一些。我很确定这对于在为星巴克设计收银机时跟踪饮料类型实际上没有用处,因为它不会很好地处理“哎呀,我的意思是黑莓味,而不是覆盆子味”.. .在装饰器模式中支持这一点需要通过几个嵌套的 Drink 装饰器进行自省,以找到需要删除的 Rasberry 装饰器。
它也不太擅长处理具有复杂相互关系的事物……如果搅打配料需要知道它与什么基础饮料类型相关联,以了解它是否应该在价格上增加 0.25 美元,那么装饰器模式就不会很有用:装饰器模式适用于各种装饰不必知道它们包装的确切实现的情况。当我们可以使用它时,它有助于减少耦合。
我真正觉得有用的东西
我认为我们使用drink 示例来解释装饰器模式主要是因为它很容易谈论在需要创建的类数量方面潜在的指数级节省,而许多实际示例说明了装饰某些东西的用处并不'实际上并没有使用装饰器模式的那个属性。
我能想到的在我们公司使用接近模式的东西的案例是我们想在流程中添加一些日志记录的案例。例如,通过装饰一个 Eclipse IProgressMonitor,我们可以检测每次显示的任务或子任务名称的变化,并记录流程的每个步骤花费的时间,这样我们就知道哪些步骤花费的时间最多。
作为装饰器这样做使我们能够访问所有日志信息,而无需更改大部分现有代码(只是要监视的作业的启动),因为它都知道如何处理 IProgressMonitor已经,而且我们也不必知道我们封装的进度监视器在内部做什么:我们不必提供替代实现,只需将现有实现封装为我们想要的附加行为。