内容简介:首先需要明确一点:装饰者模式利用了通过
装饰者模式
装饰者模式 动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
思维模式
首先需要明确一点:装饰者模式利用了 “组合”
的思想,避免了“继承”的滥用。
通过 动态地组合对象
,可以写新的代码添加新功能,而无需修改现有代码。
这就好比拼装一个机器人。
我们有各种各样的零部件:
- 躯干
- 类人的胳膊
- 带有钳子的胳膊
- 类人的腿
- 带轮子的腿
- 带履带的腿
- ……
简单粗暴的实现
想要设计各式各样的机器人,当然我们可以选择,设计一个 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() + "右下角画○->"; } }
运行Demo
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->右上角画△->左上角画□->右下角画○->
运行过程示意图:
最终得到:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。