一个故事
小明今年买了一个毛坯房,计划六月份装修作为婚房使用。小明选择了自定义的装修方案。线槽、刷漆、家具定制、门窗定制都是由不同的厂家来定制安装。
通过装饰器模式来模拟装修
- 毛坯房是一个被装饰的对象
- 线槽、刷漆、家具定制、门窗定制等就是装饰对象,他们负责对毛坯房进行装饰。
public interface House {
void decorate();
}
public class RoughHouse implements House{
@Override
public void decorate() {
System.out.println("毛坯房要开始装修了");
}
}
public abstract class HouseDecorate implements House{
protected House house;
public HouseDecorate(House house) {
this.house = house;
}
}
刷漆的装饰类
public class BrushingHouseDecorate extends HouseDecorate{
public BrushingHouseDecorate(House house) {
super(house);
}
@Override
public void decorate() {
house.decorate();
System.out.println("房屋装修------刷漆");
}
}
家具定制的装饰类
public class CustomizedFurnitureHouseDecorate extends HouseDecorate{
public CustomizedFurnitureHouseDecorate(House house) {
super(house);
}
@Override
public void decorate() {
house.decorate();
System.out.println("房屋装修------定制家具");
}
}
门窗定制的装饰类
public class DoorWindowHouseDecorate extends HouseDecorate{
public DoorWindowHouseDecorate(House house) {
super(house);
}
@Override
public void decorate() {
house.decorate();
System.out.println("房屋装修------门窗定制");
}
}
线槽安装的装饰类
public class TrunkingHouseDecorate extends HouseDecorate{
public TrunkingHouseDecorate(House house) {
super(house);
}
@Override
public void decorate() {
house.decorate();
System.out.println("房屋装修------安装线槽");
}
}
客户端
public class Client {
public static void main(String[] args) {
House house = new RoughHouse();
house = new BrushingHouseDecorate(house);
house = new TrunkingHouseDecorate(house);
house = new CustomizedFurnitureHouseDecorate(house);
house = new DoorWindowHouseDecorate(house);
house.decorate();
}
}
Result
毛坯房要开始装修了
房屋装修------刷漆
房屋装修------安装线槽
房屋装修------定制家具
房屋装修------门窗定制
如何理解装饰器模式
动态的给一个对象添加额外的职责。提供了比集成更有弹性的替代方案
- 装饰器
刷漆装修、安装线槽、定制家具、门窗定制都是属于装饰器。当我们居住一段时间后,想把厕所改造一下,我们只需要再构造一个装饰器,对房屋就是包装装饰就完成了工作,而不需要做过多的改变。 - 被装饰对象
毛坯房就是属于被装饰对象
特点
- 装饰器与被装饰对象实现同一个接口
- 装饰器持有被装饰对象的引用
- 可以随意添加装饰器
看到装饰器模式的前两个特点,我们是不是有种似曾相识的感觉,这不是静态代理的特点吗?装饰器就好比代理类,他持有被代理对象(被装饰对象)的引用,去做被代理对象能做但是不想做的事情。
装饰器模式与静态代理
- 静态代理
想做但不能做,需要找一个能干的人帮我做 - 装饰器模式
我想做,但不能做,需要找各具特色的人来帮我做
用一个例子来说明
这是一个代理类的实现
public class Proxy implements Subject{
private Subject subject;
public Proxy(Subject subject){
this.subject = subject;
}
@Override
public void request() {
this.before();
subject.request();
this.after();
}
private void before(){
System.out.println("前置处理。。。。");
}
private void after(){
System.out.println("后置处理。。。。");
}
}
如果我们想给主题添加一点操作日志,最简单的方法就是添加一个log();
private void log(){
System.out.println("添加日志");
}
对于需求,我们是不可控的,未来需求不断的增长,代理类会越来越大,难以维护,而且也不符合开闭原则。
如何应用
- 装饰器模式与静态代理模式都是包装模式,为其添加特定的功能
- 功能单一,可以选择代理模式
- 功能较多其需要动态扩张海燕,可以选择装饰器模式
装饰器模式应用场景
- Java IO流
DataInputStream in = new DataInputStream(new FileInputStream("test.txt"));
String str;
while ((str = in.readLine())!=null){
System.out.println(str);
}
in.close();
查看DataInputStream源码
public
class DataInputStream extends FilterInputStream implements DataInput {
/**
* Creates a DataInputStream that uses the specified
* underlying InputStream.
*
* @param in the specified input stream
*/
public DataInputStream(InputStream in) {
super(in);
}
......
}
public
class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in;
/**
* Creates a <code>FilterInputStream</code>
* by assigning the argument <code>in</code>
* to the field <code>this.in</code> so as
* to remember it for later use.
*
* @param in the underlying input stream, or <code>null</code> if
* this instance is to be created without an underlying stream.
*/
protected FilterInputStream(InputStream in) {
this.in = in;
}
...
}
通过源代码可以看出
- 装饰器
FilterInputStream及其子类(DataInputstream) - 被装饰对象
InputStream
由此可以设计出很多具有不同的特性的IO流。
装饰器模式的优点
- 扩展方式了灵活
- 每个装饰器互相独立不受影响
- 装饰模式是继承的替代方案,能够解决类膨胀的问题,继承是静态增加功能,装饰模式是动态增加功能。不管装饰多少层,返回的还是父类,实现的是is-a的关系。如果需要去掉某个功能,装饰模式去掉封装就可以了,但是继承就必须修改代码。
- 动态扩展装饰器类
装饰器模式的缺点
- 多层装饰比较复杂(类似剥洋葱)
网友评论