Java设计模式----装饰模式(Decorator)

来源:互联网 发布:客户达开店软件怎么样 编辑:程序博客网 时间:2024/05/16 17:29

1.什么是装饰模式

装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式
举个例子吧,咖啡是一种饮料,咖啡的本质是咖啡豆+水磨出来的。咖啡店现在要卖各种口味的咖啡,如果不使用装饰模式,那么在销售系统中,各种不一样的咖啡都要产生一个类,如果有4中咖啡豆,5种口味,那么将要产生至少20个类(不包括混合口味),非常麻烦。使用了装饰模式,只需要11个类即可生产任意口味咖啡(包括混合口味)。


2.实现方式

1).透明模式

Component.java
package cn.limbo.design_patterns.decorator;/** * 抽象界面构件类:抽象构件类,为了突出与模式相关的核心代码,对原有控件代码进行了大量的简化 * Created by limbo on 2016/12/6. */public abstract class Component {public abstract void display();}

Window.java
package cn.limbo.design_patterns.decorator.base_component;import cn.limbo.design_patterns.decorator.Component;/** * 基础的窗体类,实现了抽象的构件 * Created by limbo on 2016/12/6. */public class Window extends Component {@Overridepublic void display() {System.out.println("显示窗体!");}}

ListBox.java
package cn.limbo.design_patterns.decorator.base_component;import cn.limbo.design_patterns.decorator.Component;/** * 基础的列表框类,实现了抽象的构件 * Created by limbo on 2016/12/6. */public class ListBox extends Component {@Overridepublic void display() {System.out.println("显示列表框!");}}
TextBox.java
package cn.limbo.design_patterns.decorator.base_component;import cn.limbo.design_patterns.decorator.Component;/** * 基础的文本框类,实现了抽象的构件 * Created by limbo on 2016/12/6. */public class TextBox extends Component {@Overridepublic void display() {System.out.println("显示文本框!");}}
ComponentDecorator.java
package cn.limbo.design_patterns.decorator;/** * 构件装饰类:抽象装饰类 * Created by limbo on 2016/12/6. */public class ComponentDecorator extends Component {//维持对抽象构件类型对象的引用private Component component;//注入抽象构件类型的对象public ComponentDecorator(Component component) {this.component = component;}@Overridepublic void display() {component.display();}}

BlackBorderDecorator.java
package cn.limbo.design_patterns.decorator.decorator_component;import cn.limbo.design_patterns.decorator.Component;import cn.limbo.design_patterns.decorator.ComponentDecorator;/** * 黑色边框装饰类:具体装饰类 * Created by limbo on 2016/12/6. */public class BlackBorderDecorator extends ComponentDecorator {public BlackBorderDecorator(Component component) {super(component);}@Overridepublic void display() {this.setBlackBorder();super.display();}public void setBlackBorder() {System.out.println("为构件增加黑色边框!");}}

ScrollBarDecorator.java
package cn.limbo.design_patterns.decorator.decorator_component;import cn.limbo.design_patterns.decorator.Component;import cn.limbo.design_patterns.decorator.ComponentDecorator;/** * 滚动条装饰类:具体装饰类 * Created by limbo on 2016/12/6. */public class ScrollBarDecorator extends ComponentDecorator {public ScrollBarDecorator(Component component) {super(component);}@Overridepublic void display() {this.setScrollBar();super.display();}//装饰的方法//如果希望外部访问到装饰方法,则是半透明的装饰模式,否则为透明的装饰模式,通常建议将装饰方法设置为透明的方式,符合里氏替换原则private void setScrollBar(){System.out.println("为构件增加滚动条!");}}

DecoratorTest.java
package cn.limbo.test;import cn.limbo.design_patterns.decorator.Component;import cn.limbo.design_patterns.decorator.base_component.Window;import cn.limbo.design_patterns.decorator.decorator_component.BlackBorderDecorator;import cn.limbo.design_patterns.decorator.decorator_component.ScrollBarDecorator;import org.junit.Test;/** * Created by limbo on 2016/12/6. */public class DecoratorTest {@Testpublic void show(){Component window , scrollerBarWindow, blackBorderDecorator;//使用抽象构件定义window = new Window(); //定义基础构件,待装饰的类scrollerBarWindow = new ScrollBarDecorator(window); //定义装饰后的构件blackBorderDecorator = new BlackBorderDecorator(window);//scrollerBarWindow.display();blackBorderDecorator.display();}}


2).半透明模式

半透明模式允许客户端直接调用Decorator类中的新增方法,也就是说客户端需要区别对待抽象组件和具体的组建,举个例子就是说,你要区别对待咖啡和摩卡咖啡,虽然这样子想优点不可思议,但是现实生活中的装饰类都是这样实现的

3.优缺点

1).装饰模式的主要优点如下:

(1) 对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。

(2) 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为。

(3) 可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,得到功能更为强大的对象。

(4) 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,原有类库代码无须改变,符合“开闭原则”。


2).装饰模式的主要缺点如下:

(1) 使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,大量小对象的产生势必会占用更多的系统资源,在一定程序上影响程序的性能。

(2) 装饰模式提供了一种比继承更加灵活机动的解决方案,但同时也意味着比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为繁琐。


4.适用场景

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。
  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类定义不能继承(如final类).

5.与桥接模式的区别

个人感觉装饰模式只是为了给基础类添加新的功能。而桥接模式是存在已有的变化维度,且这个变化维度是有规律的,如变化维度可以是“红色,黄色,蓝色”等等,只是在两个变化维度中架设一座桥梁。然而装饰模式一般只有一个变化维度,而且这个变化维度是没有规律的。

6.和适配器模式的关系

 装饰模式和适配器模式都是“包装模式(Wrapper Pattern)”,它们都是通过封装其他对象达到设计的目的的,但是它们的形态有很大区别。

 

  理想的装饰模式在对被装饰对象进行功能增强的同时,要求具体构件角色、装饰角色的接口与抽象构件角色的接口完全一致。而适配器模式则不然,一般而言,适配器模式并不要求对源对象的功能进行增强,但是会改变源对象的接口,以便和目标接口相符合。

 

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



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

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


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 拼多多网上购物收不到东西怎么办 网上购物己签收但东西不好怎么办 孩子在学校学习用具总是被偷怎么办 歌华有线欠费1个月怎么办 唐小僧倒闭了百姓投的钱怎么办? 手机号被别人注册了华为账号怎么办 华为账号手机号显示已被注册怎么办 买了鑫和陌车的怎么办 注册游戏账号时乱输入的邮箱怎么办 yy频道解邦不能开直播怎么办 淘宝的淘金币快过期了怎么办 乐透啦彩票让骗了6万怎么办 交了认筹金不能进抢购平台怎么办 爱奇艺会文学会员办了想退款怎么办 海淘信用卡入账但是砍单怎么办 褐色分泌物流了好几天了怎么办? 淘宝买的衣服一直不发货怎么办 从国外寄东西到国内被税了怎么办 百度网盘上传文件数量有限制怎么办 腾讯视频上传文件过限制大小怎么办 三星s7打网页又卡又慢怎么办 路由器的上网账号和口令忘了怎么办 小米笔记本移动热点连接不上怎么办 移动宽带密码重置后认证失败怎么办 移动光纤不记得账号和密码怎么办? 宽带为什么交了钱还是不能用怎么办 小孩被虎牙直播诱导支付了款怎么办 房间里4g网络信号差怎么办 移动4g网络信号不满格怎么办 大风号无法上传视频暂停服务怎么办 过了竞牌保证金交付时间怎么办 亚马逊产品上架后货物没到怎么办 工行企业网银证书过期了怎么办 海淘转运地址国家填错了怎么办 集装箱实重与申报重量不一样怎么办 微博复制的淘口令找不到了怎么办 买了移动手机不能用联通卡怎么办 移动手机用联通卡网速慢怎么办 移动手机插联通卡没反应怎么办 移动手机办了联通大王卡怎么办 qq被冻结但是有至尊宝怎么办