装饰者模式 动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
首先需要明确一点:装饰者模式利用了 “组合”
的思想,避免了“继承”的滥用。
通过 动态地组合对象
,可以写新的代码添加新功能,而无需修改现有代码。
这就好比拼装一个机器人。
我们有各种各样的零部件:
- 躯干
- 类人的胳膊
- 带有钳子的胳膊
- 类人的腿
- 带轮子的腿
- 带履带的腿
- ……
想要设计各式各样的机器人,当然我们可以选择,设计一个 Robot
超类,然后让子类继承这个超类。
这样,我们可以得到:
- 躯干 + 人的胳膊 + 履带腿
- 躯干 + 钳子胳膊 + 轮子腿
- 躯干 + 4 个人的胳膊 + 履带腿
- ……
根据排列组合的原理,如果我们需要,Robot
的子类可以有无限多个。
假如我们从 Robot
父类处继承了一个 cost()
方法,这个方法根据该子类的 component(组件)
个数和数量来计算成本 (cost),那么我们的cost()
方法可以说要重写无数次——因为每一个子类的情况都是不一样的。
我们可以先为每一个零部件 (component) 确定成本,然后根据需要,动态地 组装(组合)
一个机器人。然后将所有的成本加起来。如此一来,不仅可以得到一个符合我们需求的 机器人对象
,更能很方便地计算 cost。
- 躯干 $100
- 类人的胳膊 $40
- 带有钳子的胳膊 $50
- 类人的腿 $70
- 带轮子的腿 $70
- 带履带的腿 $50
- ……
组合一个有 躯干 + 类人的胳膊 + 带履带的腿
的机器人的 cost
也就是:
100 + 40 + 50 = $190;
实现 组合
所谓 组合
,也就是 我中有你
。
如图所示:
通过保有各个对象的引用,即可实现“组合”
。
对于这样一个组合来的 Robot 对象,我们不妨称其为:“robotTom”。
想要求得总成本,可以直接调用robotTom.cost();
这是怎样实现的呢?
如图所示:
用公式来表示就是:
[robotTom].cost()
= [arm + body].cost() + leg.cost()
= [body].cost() + arm.cost() + leg.cost()
= body.cost() + arm.cost() + leg.cost();
这里用“leg 对象包住 arm 对象”来形容 leg 对象中有 arm 对象的引用,不过对于一个机器人而言,“leg 能包住 arm”好像有点魔幻现实的味道。
我们不妨再举一个更容易理解的例子:
我们知道,各类绘图软件中都有图层 (layer) 的概念。
每一个图层都相当于一层透明纸,我们可以在上面任意地画东西,而不会影响其他图层。
把画着东西的图层一层一层地叠放 (相当于“包装”)
起来,我们就可以得到各式各样的画作。
此时,位于上一层的图层就相当于 装饰者
,而所谓的背景图层就相当于 被装饰者
。
其中,
-
Layer
、LayerDecorator
为抽象类
-
LayerDecorator
本质上也是Layer
-
description
是各个 layer 对象的 自我描述
-
position()
表示 layer 对象在某个地方画一个图形
-
RedBackgroundLayer
、BlueBackgroundLayer
相当于 被装饰者
对应的代码:
Layer.java:
public abstract class Layer {
String description = "我是抽象 layer 父类";
public String getDescription() {return description;}
public abstract String position();}
RedBackgroundLayer.java
public class RedBackgroundLayer extends Layer {public RedBackgroundLayer (){
// 从抽象父类 layer 继承来的 description
description = "我是 RedBackgroundLayer->" ;
}
@Override
public String position() {return "我在底层画一个红色的 layer->";}
}
BlueBackgroundLayer.java
public class BlueBackgroundLayer extends Layer {public BlueBackgroundLayer() {description = "我是一个 BlueBackgroundLayer";}
@Override
public String position() {return null;}
}
各个装饰者:
RectangleLayerDecorator.java
public class RectangleLayerDecorator extends LayerDecorator {
Layer layer;
//constructor
public RectangleLayerDecorator(Layer layer) {// 这一步很重要
this.layer = layer;
}
@Override
public String getDescription() {return layer.getDescription() + "RectangleLayerDecorator->";
}
@Override
public String position() {return layer.position() + "左上角画□->";
}
}
TriangleLayerDecorator.java
public class TriangleLayerDecorator extends LayerDecorator{
Layer layer;
//constructor
public TriangleLayerDecorator(Layer layer) {this.layer = layer;}
@Override
public String getDescription() {return layer.getDescription() + "TriangleLayerDecorator->";
}
@Override
public String position() {return layer.position() + "右上角画△->";
}
}
RoundLayerDecorator.java
public class RoundLayerDecorator extends LayerDecorator {
Layer layer;
//constructor
public RoundLayerDecorator(Layer layer) {this.layer = layer;}
@Override
public String getDescription() {return layer.getDescription() + "RoundLayerDecorator->";
}
@Override
public String position() {return layer.position() + "右下角画○->";
}
}
RunDemoTest.java
public class RunDemoTest {public static void main (String[] args ){
//Step 1
Layer backgroundLayer = new RedBackgroundLayer();
System.out.println(backgroundLayer.getDescription() + backgroundLayer.position());
//Step 2
// 为 RedBackgroundLayer 装饰一个 TriangleLayerDecorator
Layer multipleLayer = new TriangleLayerDecorator(backgroundLayer);
//Step 3
// 再装饰一个 RectangleLayerDecorator
multipleLayer = new RectangleLayerDecorator(multipleLayer);
//Step 4
// 再装饰一个 RoundLayerDecorator
multipleLayer = new RoundLayerDecorator(multipleLayer);
System.out.println(multipleLayer.getDescription() + multipleLayer.position());
}
}
运行结果:
我是 RedBackgroundLayer-> 我在底层画一个红色的 layer->
我是 RedBackgroundLayer->TriangleLayerDecorator->RectangleLayerDecorator->RoundLayerDecorator-> 我在底层画一个红色的 layer-> 右上角画△-> 左上角画□-> 右下角画○->
运行过程示意图:
最终得到: