资讯专栏INFORMATION COLUMN

装饰者模式

el09xccxy / 1375人阅读

摘要:装饰者模式装饰者模式动态地将责任附加到对象上。思维模式首先需要明确一点装饰者模式利用了组合的思想,避免了继承的滥用。装饰者模式的实现我们可以先为每一个零部件确定成本,然后根据需要,动态地组装组合一个机器人。

装饰者模式
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
思维模式

首先需要明确一点:装饰者模式利用了“组合”的思想,避免了“继承”的滥用。
通过动态地组合对象,可以写新的代码添加新功能,而无需修改现有代码。

这就好比拼装一个机器人。
我们有各种各样的零部件:

躯干

类人的胳膊

带有钳子的胳膊

类人的腿

带轮子的腿

带履带的腿

……

简单粗暴的实现

想要设计各式各样的机器人,当然我们可以选择,设计一个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)的概念。
每一个图层都相当于一层透明纸,我们可以在上面任意地画东西,而不会影响其他图层。
把画着东西的图层一层一层地叠放(相当于“包装”)起来,我们就可以得到各式各样的画作。
此时,位于上一层的图层就相当于装饰者,而所谓的背景图层就相当于被装饰者

类图


其中,

LayerLayerDecorator为抽象类

LayerDecorator本质上也是Layer

description是各个layer对象的自我描述

position()表示layer对象在某个地方画一个图形

RedBackgroundLayerBlueBackgroundLayer相当于被装饰者

对应的代码:
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->右上角画△->左上角画□->右下角画○->

运行过程示意图:


最终得到:

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74811.html

相关文章

  • Java 设计模式装饰模式

    摘要:装饰者模式组成结构抽象构件给出抽象接口或抽象类,以规范准备接收附加功能的对象。装饰者模式图解装饰者模式应用场景需要扩展一个类的功能,或给一个类添加附加职责。装饰者对象接受所有来自客户端的请求。参考资料设计模式 一、了解装饰者模式 1.1 什么是装饰者模式 装饰者模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰者来包裹真实的对...

    kumfo 评论0 收藏0
  • 设计模式装饰模式

    摘要:相关设计模式装饰者模式和代理模式装饰者模式关注再一个对象上动态添加方法代理模式关注再对代理对象的控制访问,可以对客户隐藏被代理类的信息装饰着模式和适配器模式都叫包装模式关于新职责适配器也可以在转换时增加新的职责,但主要目的不在此。 0x01.定义与类型 定义:装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的...

    chuyao 评论0 收藏0
  • 设计模式——装饰模式

    摘要:装饰者模式遵循了开闭原则,对扩展开放,对修改关闭。但是在使用装饰者模式的同时可能会引入大量小类,而且使用装饰者模式除了实例化组件外,还要把组件包装进装饰者,会使代码显得不易理解。 1. 简介   装饰者模式是一种结构型模式,它可以动态的将责任附加到对象上,在扩展功能方面,它比继承更有弹性。装饰者模式遵循了开闭原则,对扩展开放,对修改关闭。  虽然在装饰者模式中也使用了继承,但是继承只是...

    hoohack 评论0 收藏0
  • 代理模式装饰模式

    摘要:简介代理模式和装饰者模式是两种常见的设计模式。这里通过构造函数的参数将被代理对象传入到代理中,也可以通过其它方式,如提供一个方法。下面是的代码输出首先依然是先创建一个需要被代理的对象,然后把它传入到的构造函数中。 简介 代理模式和装饰者模式是两种常见的设计模式。代理模式是为其它对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以...

    NusterCache 评论0 收藏0
  • 美颜相机中的设计模式 —— 装饰模式

    摘要:这是设计模式系列的第二篇,系列文章目录如下用一句话总结那些殊途同归的设计模式工厂策略模版方法美颜相机中的设计模式装饰者模式几乎所有的设计模式都是通过增加一层抽象来解决问题。 这是设计模式系列的第二篇,系列文章目录如下: 用一句话总结那些殊途同归的设计模式:工厂=?策略=?模版方法 美颜相机中的设计模式——装饰者模式 几乎所有的设计模式都是通过增加一层抽象来解决问题。 上一篇中提...

    anonymoussf 评论0 收藏0
  • JavaScript设计模式----装饰模式

    摘要:声明这个系列为阅读设计模式与开发实践曾探著一书的读书笔记装饰者模式的定义装饰者模式能够在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责。与继承相比,装饰者是一种更轻便灵活的做法。装饰者模式的作用就是为对象动态的加入某些行为。 声明:这个系列为阅读《JavaScript设计模式与开发实践》 ----曾探@著一书的读书笔记 装饰者模式的定义: 装饰者(decorator)模式能...

    rose 评论0 收藏0

发表评论

0条评论

el09xccxy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<