一、装饰者模式定义
装饰模式(Decorator Pattern)是一种比较常见的模式,其定义如下:Attach additional responsibilities to an object dynamically keeping the same interface.Decorators provide a flexible alternative to subclassing for extending functionality.(动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。)
装饰者模式的类图如下所示
Component:抽象构件,Component是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象。在装饰模式中,必然有一个最基本、最核心、最原始的接口或抽象类充当Component抽象构件。
ConcreteComponent:具体构件,ConcreteComponent是最核心、最原始、最基本的接口或抽象类的实现,你要装饰的就是它。
Decorator:装饰角色,一般是一个抽象类,做什么用呢?实现接口或者抽象方法,它里面可不一定有抽象的方法呀,在它的属性里必然有一个private变量指向Component抽象构件。
ConcreteDecorator:具体装饰类,你要把你最核心的、最原始的、最基本的东西装饰成其他东西。
只是看定义,真的是非常生涩啊,谁能看的懂啊。。。但是,没关系,看看下面的案例就明白了。
二、装饰者模式案例:来个手抓饼吧
相比我们都是吃过手抓饼(hand cake)的吧,吃手抓饼必须得打个鸡蛋(egg),加根肠(sausage),最后再来一包卫龙辣条(spicy strips)。。哦不,得两包卫龙辣条,手抓饼3块,鸡蛋2块,肠2块,两包卫龙辣条2块,一共是3+2+2+2=9块钱,用代码如何模拟实现这个过程呢?直接看使用装饰者模式如何模拟实现这个过程,类图如下
什么个意思呢,在装饰者模式中,有个很重要的角色,就是“装饰者”,在上面的图中,HandCake是被装饰者,“配料装饰者”ToppingsDecorator是装饰者,它继承HandCake,同时它内部又维护着一个成员变量HandCake的实例,以此扩展HandCake的功能:Egg、Sausage、SpicyStrips都是它的子类。
我想新增一个手抓饼类型,就继承HandCake就可以了;如果我想新增一个配料,比如鸡柳,那我就继承ToppingsDecorator就可以了。
装饰者模式通过包装对象并动态添加功能,提供了一种灵活的方式来扩展对象的行为,同时遵循开闭原则(Open-Closed Principle)和单一责任原则(Single Responsibility Principle)。
代码实现
1、被装饰者HandCake
public abstract class HandCake {
private Integer price = 0;
private String name = "";
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract Integer cost();
}
2、被装饰者具体实现ShanDongHandCake
public class ShanDongHandCake extends HandCake {
public ShanDongHandCake() {
setName("山东手抓饼");
setPrice(3);
}
@Override
public Integer cost() {
return super.getPrice();
}
}
3、装饰者ToppingsDecorator
public class ToppingsDecorator extends HandCake {
private HandCake handCake;
public ToppingsDecorator(HandCake handCake) {
this.handCake = handCake;
}
@Override
public String getName() {
return handCake.getName() + "-" + this.getName();
}
@Override
public Integer cost() {
return super.getPrice() + handCake.cost();
}
}
4、三种配料
public class Egg extends ToppingsDecorator {
public Egg(HandCake handCake) {
super(handCake);
setName("鸡蛋");
setPrice(2);
}
}
public class Sausage extends ToppingsDecorator {
public Sausage(HandCake handCake) {
super(handCake);
setName("烤肠");
setPrice(2);
}
}
public class SpicyStrips extends ToppingsDecorator{
public SpicyStrips(HandCake handCake) {
super(handCake);
setName("卫龙辣条");
setPrice(1);
}
}
5、启动类
public class Main {
public static void main(String[] args) {
HandCake order = new ShanDongHandCake();
System.out.println("一个手抓饼价格:" + order.cost());
order = new Egg(order);
System.out.println("加一个鸡蛋的价格:" + order.cost());
order = new Sausage(order);
System.out.println("加一根香肠的价格:" + order.cost());
order = new SpicyStrips(order);
System.out.println("加一包卫龙的价格:" + order.cost());
order = new SpicyStrips(order);
System.out.println("再加一包卫龙的价格:" + order.cost());
}
}
运行结果:
一个手抓饼价格:3
加一个鸡蛋的价格:5
加一根香肠的价格:7
加一包卫龙的价格:8
再加一包卫龙的价格:9
实际上上面的代码等价于下面一行代码:
HandCake order = new SpicyStrips(new SpicyStrips(new Sausage(new Egg(new ShanDongHandCake()))));
如果我想再加一个鸡蛋,那就
order = new Egg(order);
调用查询价格的方法cost()
,则是递归查询的,因为它们之间是一个聚合的关系
三、JAVA I/O框架中的装饰者模式
装饰者模式在Java语言中的最著名的应用莫过于Java I/O标准库的设计了,由于Java I/O库需要很多性能的各种组合,如果这些性能都是用继承的方法实现的,那么每一种组合都需要一个类,这样就会造成大量性能重复的类出现,而如果采用装饰者模式,那么类的数目就会大大减少,性能的重复也可以减至最少,因此装饰者模式是Java I/O库的基本模式
在Java的IO结构中,FilterInputStream 扮演的就是装饰者的角色
从类图上来看,很明显在JAVA IO框架中使用了装饰者模式:
InputStream是Component,ByteArrayInputStream和FileInputStream是ConcreteComponent,FilterInputStream是装饰者,即Decorator,DataInputStream、BufferedInputStream以及LineNumberInputStream是ConcreteDecorator。
看看下面的代码:
InputStream in = new DataInputStream(new FileInputStream(""));
InputStream in = new BufferedInputStream(new FileInputStream(""));
InputStream in = new DataInputStream(new ByteArrayInputStream(""));
InputStream in = new BufferedInputStream(new ByteArrayInputStream(""));
DataInputStream作为装饰者类,可以包装任意InputStream的子类,方便的处理其字节数据,增强了InputStream类的功能;BufferedInputStream作为装饰者类,包装了InputStream类,并提供了缓冲功能。它通过在内部维护一个缓冲区,减少了对底层输入流的直接读取次数,从而提高了读取性能。
END.
注意:本文归作者所有,未经作者允许,不得转载