在上一个装饰者模式简单实例中,可能有的朋友会觉得:使用继承不也是可以实现的嘛,干嘛这么麻烦。具体如下:
新建一个类,继承PersonBefore,然后,在子类里面调用super.eat(),也是可以直接调用父类的方法,也没有修改父类内容实现代码。
那么,这就来说说继承和装饰者模式之间的区别,为什么选择装饰者模式,而不使用继承来实现这个需求。也就是为什么装饰者设计模式会比继承好。
先来说说继承和装饰设计模式谁先出来,那必须是先是继承先出来的。
现在有以下需求:
要实现自己的一套IO系统,实现文件的读取。没必要百分百的跟jdk的功能一模一样。
首先,有 MyReader 类//专门用于读取数据的类。
为什么会有这个类呢?
因为数据类型有很多,比如文本MyTextReader,媒体MyMediaReader,等等。就会向上提取公共方法类即MyReader,可以有如下继承关系:
MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyMediaReader
。。。。。。//扩展的继续继承添加
MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader
。。。。。。//扩展的继续继承添加
问题也就随之而来了,如果再多一个子类,又得增加一个缓冲的实现子类。虽然这个体系是可以使用的。但是,扩展性不好,体系非常臃肿复杂。
那么就要对现有的体系进行优化。
所有的缓冲子类使用的技术都是相同的,没必要都给定义一个子类。现在可以直接单独定义一个缓冲类,如下:
/**
* 专门为别人提高效率而存在的,所以,此类在初始化的时候,把被提高效率的对象传进来。
*/
class MyBufferReader {
MyBufferReader(MyTextReader text) {
}
MyBufferReader(MyMediaReader media) {
}
}
/**
* 通过多态的形式。可以提高扩展性。
* 现在传入的参数就可以是MyTextReader、MyMediaReader、...
* 后期再出现新的子类,也可以接受
*/
class MyBufferReader extends MyReader {
private MyReader r;
MyBufferReader(MyReader r) {
}
}
最后,上述的继承体系,就变成了如下体系,新体系的名字就叫作装饰者模式:
MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader
装饰模式比继承要灵活。避免了继承体系臃肿。
而且降低了类于类之间的关系。(继承体系的时候,缓冲类,必须继承相应的类。现在就不需要啦,没有直接关系了。)
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。
所以装饰类和被装饰类通常是都属于一个体系中的。(可以理解为实现共同的接口,或继承一样父类)
结构上来说,由原来的继承结构,变成了现在的组合结构(我里面有你的结构)。具体怎么理解。再说吧。
装饰设计模式灵活在哪呢?
继承不要写的过多,不要以继承为主。产生子类过多,体系会显得非常臃肿。假设现在有个对象,是一年前写的,现在你新来到公司,觉得他这个类的功能不够用了。我自己写个类,把他的对象传进来,然后就可以进行加强了,当我写的功能有问题的时候,要是发现我的有问题的时候,就可以把我的注释掉,然后继续使用原来的。就如同上一次的例子里面,扩展的PersonNow的方法发生了问题,那么可以注释掉不用,继续使用PersonBefore.eat();模块功能还在。项目继续可以使用。
下面把上次的例子,做个简单的升级。
有以下四个类:
Person 共同接口,实现多态用。
PersonBefore 被装饰对象类
PersonNow 装饰类
PersonDemo 装饰模式测试类
package com.lxk.designPattern.decorator;
/**
* 公共接口(为实现多态)
*
* Created by lxk on 2016/11/24
*/
public interface Person {
void eat();
}
package com.lxk.designPattern.decorator;
/**
* 被装饰的类
* (被增强对象)
*
* Created by lxk on 2016/11/24
*/
public class PersonBefore implements Person {
@Override
public void eat() {
System.out.println("吃饭");
}
}
package com.lxk.designPattern.decorator;
/**
* 装饰类
* (要去增强目标对象的类)
* 装饰类通常会通过构造方法接收被装饰的对象。
* 并基于被装饰的对象的功能,提供更强的功能。
*
* Created by lxk on 2016/11/24
*/
public class PersonNow implements Person {
private PersonBefore p;
PersonNow(PersonBefore p) {
this.p = p;
}
@Override
public void eat() {
//简单扩展
System.out.println("开胃酒");
p.eat();
System.out.println("甜点");
System.out.println("来一根");
}
}
package com.lxk.designPattern.decorator;
/**
* 装饰设计模式:
* 当想要对已有的对象进行功能增强时,
* 可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
* 那么自定义的该类称为装饰类。
*
* 装饰类通常会通过构造方法接收被装饰的对象。
* 并基于被装饰的对象的功能,提供更强的功能。
*/
class PersonDemo {
public static void main(String[] args) {
PersonBefore p = new PersonBefore();
//p.eat();//这个是需求1.0
PersonNow sp = new PersonNow(p);
sp.eat();
}
}