首页 > 代码库 > 设计模式(五)学习----装饰模式
设计模式(五)学习----装饰模式
- 装饰设计模式:又名包装模式(Wrapper),以对客户端透明的方式扩展对象的功能,是继承关系的一种替代关系。装饰模式以对客户端透明的方式动态的给一个对象附加上更多的责任。换言之,客户端不会觉得在装饰前和装饰后有什么不同。
- 下面看装饰设计模式的UML类图:
- 在装饰模式中的各个角色:
- 抽象构件Component:给出一个抽象接口,以规范准备接收附加责任的对象。
- 具体构件角色:ConcreteComponent:定义一个要接收附加责任的类。
- 装饰角色:Decorator,实现抽象构件的接口,拥有一个抽象构件Component类型的属性,和持有抽象构件Component的对象的实例。
- 具体装饰:ConcreteDecoratorA,ConcreteDecoratorB:负责给具体构件对象“贴上”附加的责任。
- 代码实现:
抽象构件:
package com.lp.ecjtu.patten.decorator;public interface Component { public void Operation();}
具体构件:
package com.lp.ecjtu.patten.decorator;public class ConcreteComponent implements Component { @Override public void Operation() { //写相关的业务代码 }}
装饰类:
package com.lp.ecjtu.patten.decorator;public class Decorator implements Component{ //体现了聚合关系,Decorator是整体,Component部分,Decorator由Component聚合而成 private Component component;//数据类型为Component的属性 public Decorator(Component component){//构造方法传入Component组件 this.component = component; } public Decorator(){ } @Override public void Operation() { // TODO Auto-generated method stub component.Operation();//增强功能 }}
具体装饰角色:
package com.lp.ecjtu.patten.decorator;public class ConcreteDecoratorA extends Decorator { @Override public void Operation() { // TODO Auto-generated method stub super.Operation(); }}package com.lp.ecjtu.patten.decorator;public class ConcreteDecoratorB extends Decorator { @Override public void Operation() { // TODO Auto-generated method stub super.Operation(); }}
- 装饰设计模式的应用:程序员写代码,程序员除了写代码的职责,还需要其他的责任才能完成整个项目。
package com.lp.ecjtu.patten.decorator1;/** * 抽象构件 * @author Administrator * */public interface Person { public void coding();}
package com.lp.ecjtu.patten.decorator1;/** * 具体提构件类,要接收附加责任的类,程序员 * @author Administrator * */public class Employee implements Person { @Override public void coding() { System.out.println("程序员加班写程序,写程序啊,最终写完了项目。。。。"); }}
package com.lp.ecjtu.patten.decorator1;/** * 装饰类 * @author Administrator * */public class Decorator implements Person{ private Person Person; public Decorator(Person Person){ } @Override public void coding() { Person.coding(); }}
package com.lp.ecjtu.patten.decorator1;/** * 具体装饰类,项目经理A职责 * @author Administrator * */public class ManagerDecoratorA extends Decorator{ private Person person; public ManagerDecoratorA(Person person) { super(person); this.person = person; } @Override public void coding() {//增强父类coding方法的功能 doEarlyWork(); person.coding(); } private void doEarlyWork() { System.out.println("项目经理A做需求分析"); System.out.println("项目经理A做架构设计"); System.out.println("项目经理A做详细设计"); } }
package com.lp.ecjtu.patten.decorator1;/** * 具体装饰类,项目经理B * @author Administrator * */public class ManagerDecoratorB extends Decorator{ private Person person; public ManagerDecoratorB(Person person) { super(person); this.person = person; } @Override public void coding() {//增强父类coding方法的功能 doEndWork(); person.coding(); } private void doEndWork() { System.out.println("项目经理B做首尾工作"); } }
package com.lp.ecjtu.patten.decorator1;public class Client { /** * @param args */ public static void main(String[] args) {// Person employee = new Employee();//要接收户责任的对象(具体构件)// Person managerB = new ManagerDecoratorB(employee);//赋予程序员项目经理B的责任// Person managerA = new ManagerDecoratorA(managerB);//赋予程序员项目经理A的责任 new ManagerDecoratorA(new ManagerDecoratorB(new Employee())).coding();; //managerA.coding(); }}
运行结果:
项目经理A做需求分析
项目经理A做架构设计
项目经理A做详细设计
项目经理B做首尾工作
程序员加班写程序,写程序啊,最终写完了项目。。。。
分析:系统把人类Person从一个程序员Employee装饰成了项目经理B(把项目经理B的功能加到程序员身上),然后把项目经理B装饰成了项目经理A(把项目经理A的责任加到程序员+项目经理B的身上)。
如下图所示:
- 装饰模式的透明性理解:装饰模式对客户端的透明性要求程序不要声明一个ConcreteComponent(程序员)类型的变量,而要声明Component(person人类)的变量。用上面的例子理解就是必须把所人类(person)的所有装饰变化,都当做人类(person)来对待,如果把人类变化成的项目经理A当成项目经理A,那就不透明了,因为不管是项目经理A,B,还是程序员都是人类。
- 也就是说
Person employee = new Employee();//多态的方式
Person managerB = new ManagerDecoratorB(employee);
这样是对的。如果是下面的:
Employee employee = new Employee();
ManagerDecoratorB managerB = new ManagerDecoratorB(employee);
就不对了
- 装饰设计模式的优点与缺点:
- 优点:
- 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式在系统运行期动态的决定给装饰的对象动态的“贴上”一个需要的“装饰”或者除掉一个不需要的“装饰”。继承则不同,继承关系式静态的,它在系统运行前就决定了。
- 通过使用不同的具体装饰类(ManagerDecoratorA,ManagerDecoratorB,C。。。。。),以及这些装饰类的排列组合,设计师么可以设计出很多不同的行为组合。(ManagerDecoratorB装饰ManagerDecoratorA,或者用ManagerDecoratorA装饰ManagerDecoratorB)
- 缺点:
- 使用装饰模式会产生比使用继承关系更多的对象,更多的对象使得查错变得困难,特别是这些对象看上去都很像。装饰模式比继承产生更少的类。
- 设计模式在JAVA I/O库中的应用
装饰模式在Java语言中的最著名的应用莫过于Java I/O标准库的设计了。
由于Java I/O库需要很多功能的各种组合,如果这些功能都是用继承的方法实现的,那么每一种组合都需要一个类,这样就会造成大量功能重复的类出现。而如果采用装饰模式,那么类的数目就会大大减少,功能的重复也可以减至最少。因此装饰模式是Java I/O库的基本模式。
Java I/O库的对象结构图如下,由于Java I/O的对象众多,因此只画出InputStream的部分。
根据上图可以看出:
● 抽象构件(Component)角色:由InputStream扮演。这是一个抽象类,为各种子类型提供统一的接口。
● 具体构件(ConcreteComponent)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStream等类扮演。它们实现了抽象构件角色所规定的接口。
● 抽象装饰(Decorator)角色:由FilterInputStream扮演。它实现了InputStream所规定的接口。
● 具体装饰(ConcreteDecorator)角色:由几个类扮演,分别是BufferedInputStream、DataInputStream以及两个不常用到的类LineNumberInputStream、PushbackInputStream。
- 装饰模式和适配模式的区别:适配模式把一个API转化成为另一个API,而装饰模式保持被包装对象的API.
通过java Io里面的类进行讲解:
“inputStreamReader”是字节流向字符流转化的桥梁,但inputStreamReader绝对不是桥梁模式。inputStreamReader是Reader类型,它把一个InputSream的类型包装起来,从而把字节流的API转化成了字符流的API.这是适配器模式的例子。inputStreamReader把InputSream的API适配成了Reader的API.所以inputStreamReader不是装饰模式而是适配模式。同理OutputStreamWriter也是适配模式。
BUfferedReader是一个装饰类,因为它继承Reader,把Reader包装,在Reader的基础上实现了比Reader更强大的功能。但是还是Reader的API.
设计模式(五)学习----装饰模式