装饰者模式类图:
问题: 说装饰者模式比用继承会更富有弹性,在类图中不是一样用到了继承了吗?
说明:装饰者和被装饰者之间必须是一样的类型,也就是要有共同的超类。在这里应用继承并不是实现方法的复制,而是实现类型的匹配。因为装饰者和被装饰者是同一个类型,因此装饰者可以取代被装饰者,这样就使被装饰者拥有了装饰者独有的行为。根据装饰者模式的理念,我们可以在任何时候,实现新的装饰者增加新的行为。如果是用继承,每当需要增加新的行为时,就要修改原程序了。
//定义被装饰者
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.youkuaiyun.com/jason0539/article/details/22713711