装饰设计模式的由来
现在有以下需求:要实现自己的一套IO系统,实现文件的读取。没必要百分百的跟JDK的功能一模一样。
首先,MyWriter类专门用于写出数据,为什么会有这个类呢?因为数据类型有很多,比如文本MyTextWriter,媒体MyMediaWriter,等等。就会向上提取公共方法类即MyWriter,可以有如下继承关系:
MyWriter//专门用于写出数据的类
|---MyTextWriter
|---MyMediaWriter
|---。。。。。。//扩展的继续继承添加
但是又考虑到效率问题,要使用缓冲来提高效率。对写方法复写,那么又有如下继承关系。
MyWriter//专门用于写出数据的类
|---MyTextWriter
|---MyBufferedTextWriter
|---MyMediaWriter
|---MyBufferedMediaWriter
上述的体系还是是可以的。但是,这个MyWriter以后可能还会因为新的音频文件而必须新增加,那么就又有如下的继承关系图。
MyWriter//专门用于写出数据的类
|---MyTextWriter
|---MyBufferedTextWriter
|---MyMediaWriter
|---MyBufferedMediaWriter
|---MyAudioWriter
|---MyBufferedAudioWriter
|---。。。。。。//扩展的继续继承添加
问题也就随之而来了,如果再多一个子类,又得增加一个缓冲的实现子类。虽然这个体系是可以使用的,但是扩展性不好,体系非常臃肿复杂。那么就要对现有的体系进行优化。所有的缓冲子类使用的技术都是相同的,没必要都给定义一个子类。现在可以直接单独定义一个缓冲类,如下:
/**
* 专门为别人提高效率而存在的,所以,此类在初始化的时候,把被提高效率的对象传进来。
*/
class MyBufferedWriter {
MyBufferedWriter(MyTextWriter text) {
}
MyBufferedWriter(MyMediaWriter media) {
}
}
你可以这样理解:以前是有一个数据类型的类,就弄一个这个类的子类,弄个缓冲区来提高效率,来一个弄一个;现在是定义一个缓冲区,大家公用一个缓冲区,需要提高谁的效率,把谁传进来,这样公共方法就可以得到复用,如上代码所示。
但是,上面的类的实现,扩展性很差。只要添加了新数据类型,那么就得新添构造函数,所以还得继续优化。找到所有构造函数的参数的共同类型,通过多态的形式,可以提高扩展性。
/**
* 通过多态的形式可以提高扩展性。
* 现在传入的参数就可以是MyTextWriter、MyMediaWriter、...
* 后期再出现新的子类,也可以接受
*/
class MyBufferedWriter extends MyWriter {
private MyWirter w;
MyBufferedWriter(MyWirter w) {
}
}
为什么要继承MyWriter类呢?新定义的类的作用,就是带着缓冲技术的Writer,里面定义的也是写出行为,只是功能更强的写出行为。对写行为进行了增强,那么也是可以向上提升,也有写的动作,那么也是写的一份子,实现写的接口继承MyWriter也是OK的。
最后,上述的继承体系,就变成了如下体系,新体系的名字就叫作装饰者模式:
MyWriter//专门用于写出数据的类
|---MyTextWriter
|---MyMediaWriter
|---MyAudioWriter
|---MyBufferedWriter
装饰设计模式的概念
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的该类称为装饰类。装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
装饰设计模式与继承之间的优劣
装饰设计模式比继承要灵活,避免了继承体系臃肿;而且降低了类于类之间的关系(继承体系的时候,缓冲类必须继承相应的类。现在就不需要啦,没有直接关系了)。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能,所以装饰类和被装饰类通常都是属于同一个体系中的(可以理解为实现共同的接口,或继承一样父类)。结构上来说,由原来的继承结构,变成了现在的组合结构(我里面有你的结构)。
装饰设计模式的灵活之处
继承不要写的过多,不要以继承为主。产生子类过多,体系会显得非常臃肿。假设现在有个对象,是一年前写的,现在你新来到公司,觉得他这个类的功能不够用了。我自己写个类,把他的对象传进来,然后就可以进行加强了,当我写的功能有问题的时候,就可以把我的注释掉,然后继续使用原来的,模块功能还在,项目继续可以使用。
案例
有以下四个类:
Person//共同父类,实现多态用
|---Man//被装饰对象类
|---Woman//被装饰对象类
|---NewPerson//装饰类
package cn.liayun.wrapper;
/**
* 装饰设计模式:
* 当想要对已有的对象进行功能增强时,
* 可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
* 那么自定义的该类称为装饰类。
*
* 装饰类通常会通过构造方法接收被装饰的对象,
* 并基于被装饰的对象的功能,提供更强的功能。
* @author liayun
*
*/
public class PersonDemo {
public static void main(String[] args) {
// Man m = new Man();
Woman m = new Woman();
// SubMan mm = new SubMan();//子类
NewPerson mm = new NewPerson(m);
mm.chifan();
}
}
/*
Person//共同父类,实现多态用
|---Man//被装饰对象类
|---Woman//被装饰对象类
|---NewPerson//装饰类
*/
/**
* 公共父类(为实现多态)
* @author liayun
*
*/
class Person {
void chifan() {
System.out.println("吃饭");
}
}
/**
* 被装饰的类(被增强对象)
* @author liayun
*
*/
class Man extends Person {
void chifan() {
System.out.println("男人吃饭");
}
}
/**
* 被装饰的类(被增强对象)
* @author liayun
*
*/
class Woman extends Person {
void chifan() {
System.out.println("女人吃饭");
}
}
/**
* 装饰类(要去增强目标对象的类)
* 装饰类通常会通过构造方法接收被装饰的对象,
* 并基于被装饰的对象的功能,提供更强的功能。
* @author liayun
*
*/
class NewPerson extends Person {
private Person p;
NewPerson(Person p) {
this.p = p;
}
void chifan() {
System.out.println("开胃酒");
p.chifan();
System.out.println("甜点");
System.out.println("来一根");
}
}