装饰模式应用场景举例:
“K哥,我老婆说要我和她一块回去见家长,她还说她父亲大人主动要和我多喝几杯,我该怎么办啊?”GG很着急的对自己的好朋友K说道,“晕,老婆?你们 发展的也太快了吧,不过还是恭喜喔”K带着调侃的语气说道,“不过要去见家长这事情确实需要慎重的”,“按照惯例,既然对方主动的提出邀请,而且她父亲大 人都说要和你小子多喝几杯,这是非去不可的了;其实也没什么,有些心理准备就行了,我们相信GG!”K继续调侃的说道,“不过,要注意形象:-O”,“具 体要以什么形象出现呢?”GG问道,“这个你问我?我问谁啊?干脆我代你去算了”,“我是说认真的啊”GG有些着急,“这主要看你要给对方什么印象了 啊”K有些认真的说道,“具体什么印象呢?”GG问道,“一般而言,首要的是必须让对方父母知道你很爱他们的女儿;其次:年轻人都是要有活力的,开朗而阳 光;再次:要给对方家长自己很上进的印象:-O”K一脸认真的说道,“哈哈,K哥就是K哥,果然不愧是情场老大啊”,“那我具体应该穿什么呢?”GG接着 问道,“牛仔裤是一定要穿的,你平时穿的那条天蓝色牛仔裤就很棒,至于上衣忙,你现在白色的衬衫就很不错的,别忘了头发要干净,牙齿要洁白,尽量的保持你 单纯的傻傻的笑容^_^”,GG这么麻烦的问题被K三加五除二解决掉,GG兴奋的说:“老大,我爱死啦!”
装饰模式解释:
装饰( Decorator )模式又叫做包装(Wrapper)模式。通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。
英文定义为:Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
装饰模式的UML图:
建造者模式涉及以下的角色:
抽象组件(Component)角色: 一个抽象接口,是被装饰类和装饰类的父接口。
具体组件(Concrete Component)角色:为抽象组件的实现类。
抽象装饰(Decorator)角色:包含一个组件的引用,并定义了与抽象组件一致的接口。
具体装饰(Concrete Decorator)角色:为抽象装饰角色的实现类。负责具体的装饰。
装饰模式的UML图如下所示:
装饰模式深入分析:
装饰模式以一种对客服端透明的方式动态的对对象增加功能,是继承的一种很好的替代方案。
继承是一种面向对象语言特有的而且也是一种非常容易被滥用的复用和扩展的手段。继承关系必须首先符合分类学意义上的基类和子类的感谢,其次继承的子类必须 针对基类进行属性或者行为的扩展。继承使得修改或者扩展基类比较容易;但是继承也有很多不足,首先继承破坏了封装,因为继承讲基类的实现细节暴露给了子 类,其次,如果基类的实现发生了变化,那么子类也就会跟着,这时候我们就不得不改变子类的行为,来适应基类的改变。最后从基类继承而来的实现都是静态的, 不可能在运行期(runtime)发生改变,这就使得相应的系统缺乏足够的灵活性。
由于以上诸多的原因,一般尽量是不使用继承来给对象增加功能,此时,装饰模式就是一种更好的选择了,这是因为:首先,装饰模式对客户端而言是透明,客户端 根本感觉不到是原始对象还是被装饰过的对象,也就是说装饰模式对客户端而言是透明的;其次装饰者和被装饰对象拥有共同一致的接口,而且装饰者采用对被装饰 类的引用的方式使用被装饰对象,这就使得装饰对象可以无限制的动态的装饰被装饰对象;最后装饰对象并不知道被装饰对象是否被装饰过,这就使得面对任何被装 饰的对象,装饰者都可以采用一致的方式去处理。
装饰模式使用场景分析及代码实现:
在上面的使用场景中,GG要去接受MM家长的检查,要考虑如何打扮自己。首先,GG本身是一个具体的组件;其次穿上牛仔裤的GG依旧是GG,只不过是被牛 仔裤装饰了一下而已,成了牛仔男了;最后,上衣再穿上一件衬衫,这次是在牛仔男的基础上进行了进一步的装饰,此时一个阳光帅气的美男子诞生了,但是从本质 上讲,还是那个GG^_^
UML模型图如下所示:
建立一个组件接口:
package com.diermeng.designPattern.Decorator; /* * 组件的接口 */ public interface Person {
public void show();
public void noDecorator(); }
|
建立基本的装饰抽象类基类:
package com.diermeng.designPattern.Decorator;
/* * 基本的装饰抽象类基类 */ public abstract class PersonDecorator implements Person{ private Person person;
public Person getPerson() { return person; }
public void setPerson(Person person) { this.person = person; }
public PersonDecorator(Person person) { this.person = person; }
public abstract void show(); } |
具体的Person类 这里面是指GG类:
package com.diermeng.designPattern.Decorator;
/* * 具体的Person */ public class GG implements Person {
public void noDecorator() { System.out.println("我是没有经过打扮的GG"); }
public void show() { this.noDecorator(); }
}
|
蓝色牛仔裤装饰类:
package com.diermeng.designPattern.Decorator.impl;
import com.diermeng.designPattern.Decorator.Person; import com.diermeng.designPattern.Decorator.PersonDecorator; /* * 使用蓝色牛仔裤装饰 */ public class JeansDecorator extends PersonDecorator {
public JeansDecorator(Person person) { super(person); }
public void show() { this.getPerson().show(); this.jeansDecorator(); }
public void jeansDecorator() { System.out.println("我是穿上了蓝色牛仔裤的GG,帅多了O(∩_∩)O哈哈~"); }
public void noDecorator() {
}
} |
白色长衫装饰类:
package com.diermeng.designPattern.Decorator.impl;
import com.diermeng.designPattern.Decorator.Person; import com.diermeng.designPattern.Decorator.PersonDecorator; /* * 采用白色衬衫的装饰 */ public class ShirtDecorator extends PersonDecorator{
public ShirtDecorator(Person person) { super(person); }
public void show() { this.getPerson().show(); this.shirtDecorator(); }
public void shirtDecorator() { System.out.println("我是穿上了白色衬衫的GG,很靓O(∩_∩)O哈哈~"); }
public void noDecorator() {
} } |
最后我们建立测试客户端:
package com.diermeng.designPattern.Decorator.client;
import com.diermeng.designPattern.Decorator.GG; import com.diermeng.designPattern.Decorator.Person; import com.diermeng.designPattern.Decorator.impl.JeansDecorator; import com.diermeng.designPattern.Decorator.impl.ShirtDecorator; /* * 装饰模式测试客户端 */ public class DecoratorTest { public static void main(String[] args) { Person person = new GG();
person.show(); System.out.println("-------------------------------------");
Person swimcar = new JeansDecorator(person); swimcar.show(); System.out.println("-------------------------------------");
Person flySwimCar = new ShirtDecorator(swimcar); flySwimCar.show(); } } |
输出的结果如下:
我是没有经过打扮的GG ------------------------------------- 我是没有经过打扮的GG 我是穿上了蓝色牛仔裤的GG,帅多了O(∩_∩)O哈哈~ ------------------------------------- 我是没有经过打扮的GG 我是穿上了蓝色牛仔裤的GG,帅多了O(∩_∩)O哈哈~ 我是穿上了白色衬衫的GG,很靓O(∩_∩)O哈哈~
|
装饰模式的优缺点分析:
优点:
首先:使用装饰模式,能够比使用继承关系更灵活的扩展对象的功能,可以按照业务需求随意的增加对象的功能;其次:通过不同具体的装饰类以及这些具体的装饰类排列组合,可以构造出很多不同种类的装饰结果
缺点:
首先,因为装饰模式有很多装饰类,这就会使系统会是系统可以产生很对对象,产生相应的管理问题;其次,真是由于装饰模式的灵活性,使得随意组合可能 会产生很多能够正常编译和运行的对象,但是却不符合逻辑;最后,由于比较的灵活,想对于继承而言就比较的容易出错,而且出错后也不容排查出错误。
装饰模式的实际应用简介:
装饰模式使用一下场合:
想透明并且动态地给对象增加新的职责的时候。
给对象增加的职责,在未来存在增加或减少可能。
用继承扩展功能不太现实的情况下,应该考虑用组合的方式。
在Java IO库的设计和实现中就很好的使用了装饰模式。JDK提供的java.io包中使用了Decorator模式来实现对各种输入输出流的封装。以下将以java.io.OutputStream及其子类为例,讨论一下Decorator模式在IO中的使用。
我们来看一段用来创建IO流的代码:
以下是代码片段:
try {
OutputStream out = new DataOutputStream(new FileOutputStream("test.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
这段代码对于使用过JAVA输入输出流的人来说再熟悉不过了,我们使用DataOutputStream封装了一个 FileOutputStream。这是一个典型的Decorator模式的使用,FileOutputStream相当于 Component,DataOutputStream就是一个Decorator。
在java.io包中,不仅OutputStream用到了Decorator设计模式,InputStream,Reader,Writer等都 用到了此模式。而作为一个灵活的,可扩展的类库,JDK中使用了大量的设计模式,比如在Swing包中的MVC模式,RMI中的Proxy模式等等。对于 JDK中模式的研究不仅能加深对于模式的理解,而且还有利于更透彻的了解类库的结构和组成。
温馨提示:
使用装饰模式的关键是要根据实际的业务需求,针对不同的业务需求进行不同的组合,如果脱离实际的业务需要,就极有可能产生能够编译运行通过但却不符合实际逻辑的情况。
其实,对GG而言,具体穿什么是不太重要的,更重要的是GG的人品、素质等,还有一点就是个性问题。总之,表现出真我风采即可。