先不讲设计模式,先讲一个生活中的例子。山东煎饼(或者肉夹馍)相信大家都吃过,可以自己选择需要的食材,比如,可以加一串里脊,或者培根,多加个蛋,到最后,老板会根据你选择的不同食材给你算价格。其实我们可以拆分开,一个基本面饼+鸡蛋+生菜+里脊+豆奶,这就是一层一层嵌套起来,最后只要输出最终价格。这就是装饰者模式,装饰者模式本质是一种组合的思想(不同于继承的思想),多组合少继承,一层一层添加,共存的意思。
装饰者模式:动态将职责附加到对象上,若要扩展功能,装饰者提供了比继承更具弹性的代替方案。
Component是定义一个对象接口,可以给这些对象动态的添加职责。ConcreteComponent是定义一个具体的基础对象,就好比肉夹馍的白吉馍,山东煎饼的面饼。可以给这个ConcreteComponent对象添加一些职责,他就是Decorator,装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对Component来说,是无需知道Decorator的存在,至于ConcreteComponent就是具体的装饰对象,起到了给Component添加职责的功能。
下面用代码举个例子(以山东煎饼为例):
//Component用于计算这个山东煎饼有啥,多少钱
public abstract class Component {
/**
* 计算价格,整数不找零
*/
public abstract Integer calculate();
/**
* 煎饼里有啥
*/
public abstract void show();
}
上面定义一个通用接口用来抽象化增强的行为,下面定义具体的基类,山东煎饼最基础的就是一张面皮,啥都可以不要,你看到面皮,勉强认出他是山东煎饼,所以面皮就是最基础的。
public class ConcreteComponent extends Component {
/**
* 计算价格,整数不找零
*/
@Override
public Integer calculate(){
//面皮2元
return 2;
}
/**
* 煎饼里有啥
*/
@Override
public void show(){
System.out.plantln("面皮");
}
}
既然基础有了,我的装饰是啥,就是里脊、鸡蛋、生菜这些东西,所以定一个抽象的,大家都按照这个加。
public abstract class Decorator extends Component {
private Component component;
public Decorator(Component component) {
this.component = component;
}
protected abstract Integer doCalculate();
protected abstract void doShow();
/**
* 计算价格,整数不找零
*/
@Override
public Integer calculate(){
if(component != null) {
return doCalculate() + component.calculate();
}
}
/**
* 煎饼里有啥
*/
@Override
public void show(){
if(component != null) {
doShow();
component.show();
}
}
}
下面只要定义好装饰器。
//加鸡蛋
public class ConcreteDecoratorA extends Decorator {
@Override
public Integer doCalculate(){
//鸡蛋,多加2元
return 2;
}
@Override
public void doShow() {
System.out.plantln("加一个鸡蛋");
}
}
//加里脊
public class ConcreteDecoratorB extends Decorator {
@Override
public Integer doCalculate(){
//里脊,多加3元
return 3;
}
@Override
public void doShow() {
System.out.plantln("加一串里脊");
}
}
具体的用法:
void main(){
ConcreteComponent cC = new ConcreteComponent();
ConcreteDecoratorA cA = new ConcreteDecoratorA(cC);
ConcreteDecoratorB cB = new ConcreteDecoratorB(cA);
Integer calculate = cB.calculate();
cB.show();
}
与代理模式的不同
这两个设计模式看起来很像。对装饰器模式来说,装饰者(decorator)和被装饰者(decoratee)都实现同一个 接口。对代理模式来说,代理类(proxy class)和真实处理的类(real class)都实现同一个接口。此外,不论我们使用哪一个模式,都可以很容易地在真实对象的方法前面或者后面加上自定义的方法。
然而,实际上,在装饰器模式和代理模式之间还是有很多差别的。装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。可以理解成,装饰器模式是代理模式+策略模式(有可能理解的不恰当)。上面的例子是山东煎饼,如果适配一个肉夹馍,他也是可以加生菜和鸡蛋。