其实23种设计模式都是根据我们生活中演变而来的,那么我们结合生活中实实在在列子就能很快的理解帮助我们学习。
【生活实例】小林买了一套房子,买房后就需要装修,装修就很复杂了程序也很多,比如装地板,贴墙纸,装灯具,厨具安装等等,我们可以结合这个列子来学习装饰者模式。
装饰者模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。在装饰者模式中,为了让系统具有更好的灵活性和可扩展性,我们通常会定义一个抽象装饰类,而将具体的装饰类作为它的子类
【参与者】
Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
由于具体构件类和装饰类都实现了相同的抽象构件接口,因此装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。
【实例】
首先我们先创建一个House的抽象类,创建一个装饰的抽象方法,对应参与者的Component
package com.Decorator.test1;
/**
* @author 作者:李季林
* @createDate 创建时间:2019年5月6日 上午10:03:27
* 房子的抽象类
*/
public abstract class House {
/**
* 装饰的房子方法
*/
public abstract void fitment();
}
我们要装修房子,那就得先把房子购买好,创建CommonHouse类继承House抽象类,对应参与者ConcreteComponent
package com.Decorator.test1;
/**
* @author 作者:李季林
* @createDate 创建时间:2019年5月6日 上午10:17:00
*/
public class CommonHouse extends House {
@Override
public void fitment() {
// TODO Auto-generated method stub
System.out.println("小林房子买好了");
}
}
需要装修那我们还需要一个装修工人就是这个装饰抽象类Decorator,对应参与者Decorator
package com.Decorator.test1;
/**
* @author 作者:李季林
* @createDate 创建时间:2019年5月6日 上午10:05:38
* 房子的装饰类
*/
public abstract class Decorator extends House {
private House house;
public Decorator(House house) {
// TODO Auto-generated constructor stub
this.house=house;
}
@Override
public void fitment() {
// TODO Auto-generated method stub
this.house.fitment();
}
}
接下来我们就需要准备具体的装修类,如地板Floor、墙纸Wallpaper、灯具Lamp等对应参与者ConcreteDecorator
创建地板装饰类FloorDecorator
package com.Decorator.test1;
/**
* @author 作者:李季林
* @createDate 创建时间:2019年5月6日 上午10:18:03
* 装饰地板
*/
public class FloorDecorator extends Decorator {
public FloorDecorator(House house) {
// TODO Auto-generated constructor stub
super(house);
}
@Override
public void fitment() {
// TODO Auto-generated method stub
super.fitment();
System.out.println("装饰了地板");
}
}
创建墙纸装饰类WallpaperDecorator
package com.Decorator.test1;
/**
* @author 作者:李季林
* @createDate 创建时间:2019年5月6日 上午10:19:35
* 墙纸装饰
*/
public class WallpaperDecorator extends Decorator {
public WallpaperDecorator(House house) {
// TODO Auto-generated constructor stub
super(house);
}
@Override
public void fitment() {
// TODO Auto-generated method stub
super.fitment();
System.out.println("装饰了墙纸");
}
}
创建灯具装饰类LampDecorator
package com.Decorator.test1;
/**
* @author 作者:李季林
* @createDate 创建时间:2019年5月6日 上午10:21:38
*/
public class LampDecorator extends Decorator {
public LampDecorator(House house) {
// TODO Auto-generated constructor stub
super(house);
}
@Override
public void fitment() {
// TODO Auto-generated method stub
super.fitment();
System.out.println("装饰了灯");
}
}
接下里对上面代码进行测试
package com.Decorator.test1;
/**
* @author 作者:李季林
* @createDate 创建时间:2019年5月6日 上午10:22:31
*/
public class DecoratorTest {
public static void main(String[] args) {
//准备基本类,购买房子
CommonHouse commonHouse=new CommonHouse();
//装修地板
FloorDecorator floorHouse=new FloorDecorator(commonHouse);
//装修墙纸
WallpaperDecorator wallpaperHouse=new WallpaperDecorator(floorHouse);
//装修灯具
LampDecorator lampDecorator=new LampDecorator(wallpaperHouse);
lampDecorator.fitment();
}
}
打印结果:
小林房子买好了
装饰了地板
装饰了墙纸
装饰了灯
【总结】装饰模式在一些类与类之间有叠加效应(也就是给一个类增加附加功能)的场景中非常好用,它可以说是继承的替代品,有更好的扩展性,也比较灵活。在 Java JDK 源码中也大面积用到了装饰模式,比如java.io.BufferedInputStream(InputStream)。