设计模式之装饰者模式
来源:互联网 发布:生产管理工程师 知乎 编辑:程序博客网 时间:2024/05/16 02:52
装饰者模式类图:
问题: 说装饰者模式比用继承会更富有弹性,在类图中不是一样用到了继承了吗?
说明:装饰者和被装饰者之间必须是一样的类型,也就是要有共同的超类。在这里应用继承并不是实现方法的复制,而是实现类型的匹配。因为装饰者和被装饰者是同一个类型,因此装饰者可以取代被装饰者,这样就使被装饰者拥有了装饰者独有的行为。根据装饰者模式的理念,我们可以在任何时候,实现新的装饰者增加新的行为。如果是用继承,每当需要增加新的行为时,就要修改原程序了。
//定义被装饰者 public interface Human { public void wearClothes(); public void walkToWhere(); } //定义装饰者 public abstract class Decorator implements Human { private Human human; public Decorator(Human human) { this.human = human; } public void wearClothes() { human.wearClothes(); } public void walkToWhere() { human.walkToWhere(); } } //下面定义三种装饰,这是第一个,第二个第三个功能依次细化,即装饰者的功能越来越多 public class Decorator_zero extends Decorator { public Decorator_zero(Human human) { super(human); } public void goHome() { System.out.println("进房子。。"); } public void findMap() { System.out.println("书房找找Map。。"); } @Override public void wearClothes() { // TODO Auto-generated method stub super.wearClothes(); goHome(); } @Override public void walkToWhere() { // TODO Auto-generated method stub super.walkToWhere(); findMap(); } } public class Decorator_first extends Decorator { public Decorator_first(Human human) { super(human); } public void goClothespress() { System.out.println("去衣柜找找看。。"); } public void findPlaceOnMap() { System.out.println("在Map上找找。。"); } @Override public void wearClothes() { // TODO Auto-generated method stub super.wearClothes(); goClothespress(); } @Override public void walkToWhere() { // TODO Auto-generated method stub super.walkToWhere(); findPlaceOnMap(); } } public class Decorator_two extends Decorator { public Decorator_two(Human human) { super(human); } public void findClothes() { System.out.println("找到一件D&G。。"); } public void findTheTarget() { System.out.println("在Map上找到神秘花园和城堡。。"); } @Override public void wearClothes() { // TODO Auto-generated method stub super.wearClothes(); findClothes(); } @Override public void walkToWhere() { // TODO Auto-generated method stub super.walkToWhere(); findTheTarget(); } } //定义被装饰者,被装饰者初始状态有些自己的装饰 public class Person implements Human { @Override public void wearClothes() { // TODO Auto-generated method stub System.out.println("穿什么呢。。"); } @Override public void walkToWhere() { // TODO Auto-generated method stub System.out.println("去哪里呢。。"); } } //测试类,看一下你就会发现,跟java的I/O操作有多么相似 public class Test { public static void main(String[] args) { Human person = new Person(); Decorator decorator = new Decorator_two(new Decorator_first( new Decorator_zero(person))); decorator.wearClothes(); decorator.walkToWhere(); } }
运行结果:
其实就是进房子找衣服,然后找地图这样一个过程,通过装饰者的三层装饰,把细节变得丰富。
关键点:1、Decorator抽象类中,持有Human接口,方法全部委托给该接口调用,目的是交给该接口的实现类即子类进行调用。
2、Decorator抽象类的子类(具体装饰者),里面都有一个构造方法调用super(human),这一句就体现了抽象类依赖于子类实现即抽象依赖于实现的原则。因为构造里面参数都是Human接口,只要是该Human的实现类都可以传递进去,即表现出Decorator dt = new Decorator_second(new Decorator_first(new Decorator_zero(human)));这种结构的样子。所以当调用dt.wearClothes();dt.walkToWhere()的时候,又因为每个具体装饰者类中,都先调用super.wearClothes和super.walkToWhere()方法,而该super已经由构造传递并指向了具体的某一个装饰者类(这个可以根据需要调换顺序),那么调用的即为装饰类的方法,然后才调用自身的装饰方法,即表现出一种装饰、链式的类似于过滤的行为。
3、具体被装饰者类,可以定义初始的状态或者初始的自己的装饰,后面的装饰行为都在此基础上一步一步进行点缀、装饰。
4、装饰者模式的设计原则为:对扩展开放、对修改关闭,这句话体现在我如果想扩展被装饰者类的行为,无须修改装饰者抽象类,只需继承装饰者抽象类,实现额外的一些装饰或者叫行为即可对被装饰者进行包装。所以:扩展体现在继承、修改体现在子类中,而不是具体的抽象类,这充分体现了依赖倒置原则,这是自己理解的装饰者模式。
Java I/O使用装饰模式设计:
FilterInputStream为装饰模式中的Decorator,FilterInputStream是一个普通的Java类,不是接口也不是抽象类
public class FilterInputStreamextends InputStream{ protected InputStream in; protected FilterInputStream(InputStream in){ this.in = in; } ... }
在InputStream提供的基本方法的基础上,FilterInputStream的子类提供了更多附加功能,例如:
BufferedInputStream类会提供一个内部的字节数组作为输入缓存
通过DataInputStream类,可以用与机器无关的方式从底层数据流中读取基本Java数据类型
LineNumberInputStream类可以跟踪当前行号
一个提供输入缓存、并且能够获取输入文件流行数的小程序:
- import java.io.BufferedInputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.InputStream;
- import java.io.LineNumberInputStream;
- public class Test {
- public static void main(String[] args) {
- try {
- InputStream in = new FileInputStream(new File("c:\\seanApp\\test.txt"));
- BufferedInputStream in1 = new BufferedInputStream(in);
- LineNumberInputStream in2 = new LineNumberInputStream(in1);
- int result = in2.read();
- while(result != '\n'){
- result = in2.read();
- }
- System.out.println(in2.getLineNumber());//2
- in2.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
当然也可以通过继承FilterInputStream类来实现自己的装饰者:
- import java.io.BufferedInputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FilterInputStream;
- import java.io.IOException;
- import java.io.InputStream;
- //We can read the string directly by this class
- public class MyInputStream extends FilterInputStream {
- protected MyInputStream(InputStream in) {
- super(in);
- }
- public int read(String str) throws IOException {
- byte[] bs = str.getBytes();
- return super.read(bs);
- }
- public static void main(String[] args){
- try {
- InputStream in = new FileInputStream(new File("c:\\seanApp\\test.txt"));
- BufferedInputStream in2 = new BufferedInputStream(in);
- MyInputStream in3 = new MyInputStream(in2);
- in3.read("Just a test!!!");
- in3.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
JDK中还有很多类是使用装饰模式设计的,如:Reader类、Writer类、OutputStream类等,如果使用这种结构,那么在基础方法上添加新的功能将十分简单
例如:java.io.Reader:
FilterReader是一个抽象类,可以很方便的进行扩展
点击打http://www.cnblogs.com/ASPNET2008/archive/2008/06/15/1222724.html
http://blog.csdn.net/jason0539/article/details/22713711
- 设计模式之装饰者设计模式
- 设计模式 之 装饰者
- 设计模式之装饰者模式
- 设计模式之装饰者模式
- 设计模式之Decorator(装饰者模式)
- 设计模式之五---装饰者模式
- 设计模式之---装饰者模式
- c++设计模式之装饰者模式
- Php设计模式之装饰者模式
- java设计模式之装饰者模式
- 设计模式之装饰者模式
- 【设计模式】之装饰者模式
- HeadFirst设计模式之装饰者模式
- c++设计模式之装饰者模式
- 设计模式之装饰者模式
- 设计模式之--装饰者模式
- 设计模式之装饰者模式
- 设计模式之装饰者模式
- 如何利用python生成随机验证码?
- 文件系统
- CFileDialog 打开目录文件 保存目录文件
- 100行lua代码实现简单目录浏览器
- javascript闭包的理解
- 设计模式之装饰者模式
- BFS-记录路径
- 好久不开杂博突然发现简历里没东西可写了
- Qt开发实例-贪吃蛇
- CSS权威指南-链接伪类
- ReactJs实战-让人沮丧的HelloWorld
- 12-002-2 XML文件的建立或者xml文件的本地输出(保存)
- 第二天的打字练习
- Add Digits