转自:http://blog.csdn.net/eric_sunah/article/details/10164707
在说明什么是Decorator模式之前,先来看看它有什么优点,通过下面的例子你或许会对它有一个简单的认识
需求背景
设计一个Modem(调制解调器)的层次结构,在这个结构中
(1) Modem基类包含了一些调制解调器常用的功能,比如拨号,音量的控制
(2) 子类一:LoudModem,一般的拨号器在拨号的时候是没有声音的,这种modem在拨号的时候会发出声音
(3) 子类二:ScreenModem,一般的拨号器在拨号的时候是不会把号码显示在屏幕上的,这种modem在拨号的时候会将号码显示在屏幕上
方案一:继承
这是一种比较容易想到的方案,对于简单且稳定的业务场景这或许是个很好的选择,大概的类图如下
BaseModem实现了Modem接口中的方法,然后LoundModem,PrintModem都继承自BaseModem,根据需求分别覆盖dial方法
缺点
当子类的需求发生变化时,例如LoudModem也要求实现print的功能,这时只能修改LoudModem的dial方法,这时就违反了OCP(开放封闭原则)
如果有多个子类,每个子类都要求添加print的功能,那么这些子类的dial方法都需要进行修改,对于软件维护而言这或许是个噩梦的开始
方案二:Decorator模式
分析
将Modem的拨号特性 "Loud""Print" 都作为一个个单独的装饰类,当某个子类需要某个一些特性时,就直接用专门的装饰类来装饰它,且装饰的效果是可以叠加的.
例如 对于一个既有声音又能打印的modem而言,只需要用Loud以及Print这两个装饰器来装饰它既可,如果要想添加新的效果,只需要开发一个新的装饰器,然后用这个装饰器来装饰对应的子类便可,对于已经存在的代码不需要做任何的改动.
类图如下
从类图可以看出,每个Decorator都有一个dial方法,且都包含一个Modem的成员变量,具体的应用请参考下面的代码
样例代码
Modem接口类
- package com.eric.designmodel.decorator;
-
- public interface Modem {
- public void dial(String number);
-
- public void setSpeakVolumn(int volumn);
-
- public String getPhoneNumber();
-
- public int getSpeakVolumn();
- }
BaseModem基类
- package com.eric.designmodel.decorator;
-
- public class BaseModem implements Modem {
-
- private String number;
- private int volumn;
-
- @Override
- public void dial(String number) {
- this.number = number;
- }
-
- @Override
- public void setSpeakVolumn(int volumn) {
- this.volumn = volumn;
- }
-
- @Override
- public String getPhoneNumber() {
- return number;
- }
-
- @Override
- public int getSpeakVolumn() {
- return volumn;
- }
-
- }
HayesModem 子类
-
-
-
- package com.eric.designmodel.decorator;
-
-
-
-
-
-
-
-
-
- public class HayesModem extends BaseModem {
-
- }
LoudDecorator装饰类
- package com.eric.designmodel.decorator;
-
-
-
-
-
-
-
-
-
- public class LoudDecorator implements Modem {
-
- private Modem modem;
-
- public LoudDecorator(Modem modem) {
- this.modem = modem;
- }
-
- @Override
- public void dial(String number) {
- modem.setSpeakVolumn(10);
- modem.dial(number);
- }
-
- @Override
- public void setSpeakVolumn(int volumn) {
- modem.setSpeakVolumn(volumn);
- }
-
- @Override
- public String getPhoneNumber() {
- return modem.getPhoneNumber();
- }
-
- @Override
- public int getSpeakVolumn() {
- return modem.getSpeakVolumn();
- }
-
- }
ScreenDecorator装饰类
- package com.eric.designmodel.decorator;
-
-
-
-
-
-
-
-
-
- public class ScreenDecorator implements Modem {
- public static final String NUMBER_PREFIX = "025+";
- private Modem modem;
-
- public ScreenDecorator(Modem modem) {
- this.modem = modem;
- }
-
- @Override
- public void dial(String number) {
- modem.dial(NUMBER_PREFIX + number);
- }
-
- @Override
- public void setSpeakVolumn(int volumn) {
- modem.setSpeakVolumn(volumn);
- }
-
- @Override
- public String getPhoneNumber() {
- return modem.getPhoneNumber();
- }
-
- @Override
- public int getSpeakVolumn() {
- return modem.getSpeakVolumn();
- }
- }
测试类
- package com.eric.designmodel.decorator;
-
- import junit.framework.TestCase;
-
-
-
-
-
- public class MainTest extends TestCase {
- private static final String NUMBER = "10";
-
- public void testNoneDecotarot() {
- Modem modem = new HayesModem();
- modem.dial(NUMBER);
- assertTrue(modem.getSpeakVolumn() == 0);
- assertTrue(modem.getPhoneNumber().equals(NUMBER));
- }
-
-
-
-
- public void testLoudDecotarot() {
- Modem modem = new HayesModem();
- LoudDecorator loudModem = new LoudDecorator(modem);
- loudModem.dial(NUMBER);
- assertTrue(loudModem.getSpeakVolumn() == 10);
- assertTrue(loudModem.getPhoneNumber().equals(NUMBER));
-
- }
-
-
-
-
- public void testScreenDecotarot() {
- Modem modem = new HayesModem();
- ScreenDecorator loudModem = new ScreenDecorator(modem);
- loudModem.dial(NUMBER);
- assertTrue(loudModem.getSpeakVolumn() == 0);
- assertTrue(loudModem.getPhoneNumber().startsWith(ScreenDecorator.NUMBER_PREFIX));
-
- }
-
-
-
-
- public void testDoubleDecotarot() {
- Modem modem = new HayesModem();
- Modem screenModem = new ScreenDecorator(modem);
- Modem loudModem = new LoudDecorator(screenModem);
- loudModem.dial(NUMBER);
- assertTrue(loudModem.getSpeakVolumn() == 10);
- assertTrue(loudModem.getPhoneNumber().startsWith(ScreenDecorator.NUMBER_PREFIX));
- }
- }
优点
将每个特性都作为一个单独的装饰类,在需求发生变化的时候对特性进行动态的组合.且不需要修改具体的子类.
个人觉得该模式对比Proxy模式而言强大之处在于可以把多个装饰效果应用到某个子类中.
应用
Decorator模式java的stand lib中也被广泛的应用,例如: Java中的IO是明显的装饰器模式的运用。FilterInputStream,FilterOutputStream,FilterRead,FilterWriter分别为具体装饰器的父类,相当于Decorator类,它们分别实现了InputStream,OutputStream,Reader,Writer类(这些类相当于Component,是其他组件类的父类,也是Decorator类的父类)。继承自InputStream,OutputStream,Reader,Writer这四个类的其他类是具体的组件类,每个都有相应的功能,相当于ConcreteComponent类。而继承自FilterInputStream,FilterOutputStream,FilterRead,FilterWriter这四个类的其他类就是具体的装饰器对象类,即ConcreteDecorator类。通过这些装饰器类,可以给我们提供更加具体的有用的功能。如FileInputStream是InputStream的一个子类,从文件中读取数据流,BufferedInputStream是继承自FilterInputStream的具体的装饰器类,该类提供一个内存的缓冲区类保存输入流中的数据。我们使用如下的代码来使用BufferedInputStream装饰FileInputStream,就可以提供一个内存缓冲区来保存从文件中读取的输入流。
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
-
-
相关推荐
“[设计模式]在实用环境下特别有用,因为它分类描述了一组设计良好,表达清楚的面向对象软件设计模式。整个设计模式领域还很新,本书的四位作者也许已占据了这个领域造诣最深的专家中的半数,因而他们定义模式的方法...
主要介绍了Python中设计模式之Decorator装饰器模式模式,文中详细地讲解了装饰对象的相关加锁问题,需要的朋友可以参考下
“就增加功能来说,Decorator 模式相比生成子类更为灵活” 这句话的含义是,组合比继承更灵活,当可拓展的功能很多时,继承方案会产生大量的子类,而组合可以提
C#面向对象设计模式纵横谈(10):Decorator 装饰模式(结构型模式) C#面向对象设计模式纵横谈(11):Facade 外观模式(结构型模式) C#面向对象设计模式纵横谈(12):Flyweight 享元模式(结构型模式) C#面向对象设计...
c++设计模式-结构型模式-装饰器模式;QT工程;c++简单源码; 装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
23种Python设计模式示例演示源码包,比如包括了工厂模式、Bridge桥接模式、Builder构建模式、Facade外观模式、Adapter适配器模式,Composite组合模式、Decorator装饰器模式,FactoryMethod工厂方法模式、Flyweight享...
书名: 设计模式可复用面向对象软件的基础 英文原书名: Design Patterns:Elements of Reusable Object-Oriented software 作者: Erich Gamma 等 译者: 李英军 马晓星 蔡敏 刘建中 书号: 7-111-07575-7 页码: 254 定价...
主要为大家详细介绍了java设计模式之装饰器模式Decorator,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 这种模式创建了一个装饰类,用来包装原有的类,并在...
主要介绍了Java设计模式之装饰模式(Decorator模式)介绍,本文讲解了为什么使用Decorator、如何使用装饰模式、Jive中的Decorator实现等内容,需要的朋友可以参考下
控制访问,装饰器设计的四个名词,装饰器模式与代理模式的区别,
主要介绍了PHP设计模式:装饰器模式Decorator,结合实例形式分析了PHP装饰器模式Decorator相关概念、功能、原理、用法及操作注意事项,需要的朋友可以参考下
创建型模式用来处理对象的创建过程,主要包含以下5种设计模式: 工厂方法模式(Factory Method Pattern) 抽象工厂模式(Abstract Factory Pattern) 建造者模式(Builder Pattern) 原型模式...
C#设计模式(12)-Decorator Pattern 101 一、 装饰(Decorator)模式 101 二、 装饰模式的结构 102 三、 装饰模式示例性代码 103 四、 装饰模式应当在什么情况下使用 106 五、 装饰模式实际应用的例子 106 六、 ...
23种设计模式(Design Pattern)的C++实现范例,包括下面列出的各种模式,代码包含较详细注释。另外附上“设计模式迷你手册.chm” 供参考。 注:项目在 VS2008 下使用。 创建型: 抽象工厂模式(Abstract Factory) ...
第22章 装饰模式(Decorator) 第23章 职责链模式(Chain of Responsibility) 第24章 桥接模式(Bridge) 第25章 访问者模式(Visitor) 附录A常见面向对象设计原则 附录BUML简介 参考文献
本文实例讲述了PHP设计模式之装饰器模式定义与用法。分享给大家供大家参考,具体如下: 什么是装饰器模式 作为一种结构型模式, 装饰器(Decorator)模式就是对一个已有结构增加”装饰”. 适配器模式, 是为现在有结构...
装饰器模式(Decorator Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 代理模式(Proxy Pattern) 3 行为型模式 这些设计模式特别关注对象之间的通信。 责任链模式(Chain of ...
装饰器模式(Decorator Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 代理模式(Proxy Pattern) 3. 行为型模式 责任链模式(Chain of Responsibility Pattern) 命令模式(Command ...