您的位置:首页 > 其它

设计模式之装饰者模式

2016-06-24 22:19 351 查看
     装饰者模式 :动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
     装饰者模式类图:

          


  

 

    问题:  说装饰者模式比用继承会更富有弹性,在类图中不是一样用到了继承了吗?

    说明:装饰者和被装饰者之间必须是一样的类型,也就是要有共同的超类。在这里应用继承并不是实现方法的复制,而是实现类型的匹配。因为装饰者和被装饰者是同一个类型,因此装饰者可以取代被装饰者,这样就使被装饰者拥有了装饰者独有的行为。根据装饰者模式的理念,我们可以在任何时候,实现新的装饰者增加新的行为。如果是用继承,每当需要增加新的行为时,就要修改原程序了。

//定义被装饰者
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类可以跟踪当前行号

一个提供输入缓存、并且能够获取输入文件流行数的小程序:

[java]
view plain
copy

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类来实现自己的装饰者:

[java]
view plain
copy

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://blog.csdn.net/a19881029/article/details/8990655

点击打http://www.cnblogs.com/ASPNET2008/archive/2008/06/15/1222724.html

http://blog.csdn.net/jason0539/article/details/22713711
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: