博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
装饰模式(Decorator) ...
阅读量:7117 次
发布时间:2019-06-28

本文共 3210 字,大约阅读时间需要 10 分钟。

述:

装饰模式又名包装(Wrapper)模式,是以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。

 

意图:

动态方式给一个对象附加更多的功能。装饰模式可以在不创造更多的子类的情况下扩张对象的功能。动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活(为什么比继承要好,后面会讲到)。

实现对客户端透明 (怎么实现,后面会讲到)

 

实质:

      实现对客户端透明的方式扩展对象的功能。

使用场景:

主要是解决:“过度地使用了继承来扩展对象的功能”,由于继承为类型引入的静态特质(以继承的方式使某一类型要获得功能是在编译时是静态的,动态,是指在运行时),使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀(多继承)。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

我的理解:我们要扩展对象的功能(即对已有功能动态添加更多功能)而且还要实现对客户端透明这个是本质。

如果我们可以继承ConcreteComponent,生成A, B, C;如果客户端需要功能不确定,动态的,有可能是A、AC、CAB等等。由于实现对客户端透明,所以得继续扩充产生AC、CAB等等。这样的话虽然功能可以实现,但以后继续扩充会导致子类的膨胀,而且代码的重用性很差,所以不能通过继承来扩充功能。如果ConcreteComponent被隐藏(我们访问不到)或者不能生成子类。这样的话我们根本就不能通过继承来扩充功能。

透明性: 要求客户端的程序不要声明一个ConcreteComponent类型的变量,而应当声明一个Component接口类型的变量。

我们要扩展对象的功能(对已有功能动态扩充添加)但又不能继承(这里是指不能继承ConcreteComponent来扩展功能)。意味着需要把它的功能进行装饰,所以只能是has-a的关系,由于我们需要Operation方法名调用ConcreteComponent的Operation,所以要继承Component接口,以实现对客户端的透明。

 

参与者:

  • 抽象构件角色(Component):定义一个对象接口,可以给这些对象动态地添加职责。
  • 具体构件角色(Concrete Component):定义了一个具体的对象,也可以给这个对象添加一些职责。
  • 装饰角色(Decorator):持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的抽象类。
  • 具体装饰角色(Concrete Decorator):具体的装饰对象,起到给Component添加职责的功能

UML图:

装饰模式的简化

如果只有一个ConcreteComponent类,那么可以考虑去掉抽象的Component类(接口),把Decorator作为一个ConcreteComponent子类。如下图所示:

 

如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。甚至在只有两个ConcreteDecorator类的情况下,都可以这样做。如下图所示:

基本条件:

View Code
public interface Component        {             void Operation();        }        public class ConcreteComponent : Component        {            public void Operation()            {                //已有的功能            }        }

装饰模式:

View Code
public abstract class Decorator : Component        {            private Component component;            public void SetComponent(Component component)            {                this.component = component;            }            public virtual void Operation()            {                if (component != null)                    component.Operation();            }        }        public class ConcreteDecoratorA : Decorator        {            private string AddedState;            public override void Operation()            {                base.Operation();                AddedState = "装饰模式";            }        }        public class ConcreteDecoratorB : Decorator        {            public override void Operation()            {                base.Operation();                AddedBehavior();            }            private void AddedBehavior()            {                //添加功能            }        }

优点:

  • 装饰模式提供了更加灵活的向对象添加职责的方式。在运行时装饰需要的职责,组合出复杂的功能。
  • 把类中装饰功能从类中搬移去除,简化了原有类,有效地把核心职责和装饰功能区分开了,增加了代码的重用性。

 

缺点:

  • 客户端需要自己去组合要装饰的功能。

 

装饰模式与适配器模式:                         

半透明装饰模式:客户端可以声明ConcreteDecorator类型的变量,从而可以调用ConcreteDecorator类中才有的方法。

装饰模式有透明和半透明两种,这两种的区别就在于装饰角色的接口与抽象构件角色的接口是否完全一致。透明的装饰模式也就是理想的装饰模式,要求具体构件角色、装饰角色的接口与抽象构件角色的接口完全一致。相反,如果装饰角色的接口与抽象构件角色接口不一致,也就是说装饰角色的接口比抽象构件角色的接口宽的话,装饰角色实际上已经成了一个适配器角色,这种装饰模式也是可以接受的,称为“半透明”的装饰模式,如下图所示。

 

  在适配器模式里面,适配器类的接口通常会与目标类的接口重叠,但往往并不完全相同。换言之,适配器类的接口会比被装饰的目标类接口宽。

  显然,半透明的装饰模式实际上就是处于适配器模式与装饰模式之间的灰色地带。如果将装饰模式与适配器模式合并成为一个“包装模式”的话,那么半透明的装饰模式倒可以成为这种合并后的“包装模式”的代表。

 

总结:以上纯属个人的理解,对于有些地方觉得还是理解不是很深,有不足之处和错误的地方希望大家帮我指出。谢谢

 

转载于:https://www.cnblogs.com/gyb333/archive/2012/12/18/DecoratorPattern.html

你可能感兴趣的文章
mybatis+dubbo+ springmvc+zookeeper分布式架构
查看>>
MJRefresh源码解读
查看>>
easyui tabs切换和单个页面手动刷新以及点击添加新的tabs
查看>>
一天4-5小时睡眠也可以高效工作
查看>>
图形化编程语言的设计
查看>>
实现一个前端路由,如何实现浏览器的前进与后退 ?
查看>>
面试题 async/await
查看>>
多线程协作wait、notify、notifyAll方法简介理解使用 多线程中篇(十四)
查看>>
Handler源码剖析
查看>>
微服务监控神器Prometheus的安装部署
查看>>
Python3 爬虫
查看>>
java常用多线程创建方式
查看>>
【刘文彬】【精解】EOS标准货币体系与源码实现分析
查看>>
MySQL入门系列:数据的插入、删除和更新
查看>>
小程序导出朋友圈海报详细记录
查看>>
dubbo集群之Cluster模块
查看>>
[译] SwiftUI 官方教程 (五)
查看>>
centOS7 安装Git
查看>>
css3打包后自动追加前缀插件:autoprefixer
查看>>
移动端反馈样式
查看>>