设计模式-Decorator模式

目录

  • 一个例子(贪玩蓝月)
  • 传统继承实现
  • 装饰器模式实现
  • 对比
  • 总结

Decorator(装饰器)模式属于结构型模式。
比如当其需要三种不同的附加特性,可以为其创建三个派生类。但是若它还需要同时具有其中两种特性或者是各种特性的任意组合的时候,类继承的方法就不再适合了。
它允许向一个现有的对象不通过继承来添加新的功能,同时又不改变其结构。

一个例子(贪玩蓝月)

前一阵子张家辉代言的《贪玩蓝月》广告火了,“我系喳喳辉,是兄弟就来砍我~”被洗脑到现在,正好用这个游戏来解释一下装饰器模式。

玩游戏的人都知道这种类传奇的游戏核心玩法就是买装备,打怪,升级,买装备这样反复。

刚注册账号进入游戏的玩家假设只有一条大裤衩,价值5金币,随着刷怪升级,身上的装备也在一件件增多,这时候我们需要知道身上的装备价值多少金币。

定义玩家

public interface Gamer {
    /**
     * 获取目前的装备
     * @return
     */
    String getEquip();

    /**
     * 获取目前身上装备的价格
     * @return
     */
    int getPrice();
}

定义具体的法师职业玩家

public class MasterGamer implements Gamer {
    /**
     * 获取目前的装备
     *
     * @return
     */
    @Override
    public String getEquip() {
        return "大裤衩";
    }

    /**
     * 获取目前身上装备的价格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return 5;
    }
}

新法师玩家出门只有大裤衩,装备全靠打。

传统继承实现

装备“法师权杖”

public class TruncheonMasterGamer extends MasterGamer{
    /**
     * 获取目前的装备
     *
     * @return
     */
    @Override
    public String getEquip() {
        return super.getEquip()+",法师权杖";
    }

    /**
     * 获取目前身上装备的价格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return super.getPrice()+50;
    }
}

继续装备“魔法斗篷”

public class CloakTruncheonMasterGamer extends TruncheonMasterGamer{
    /**
     * 获取目前的装备
     *
     * @return
     */
    @Override
    public String getEquip() {
        return super.getEquip()+",魔法斗篷";
    }

    /**
     * 获取目前身上装备的价格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return super.getPrice()+80;
    }
}

注意,这里是在之前已经装备了“法师权杖”之上去继承。

计算装备价格

CloakTruncheonMasterGamer gamer = new CloakTruncheonMasterGamer();
System.out.println("当前装备:"+gamer.getEquip()+"\n装备总价值:"+gamer.getPrice());

输出结果

当前装备:大裤衩,法师权杖,魔法斗篷
装备总价值:135

装饰器模式实现


声明通用装饰器基类“装备”

public abstract class Equip implements Gamer {
    private Gamer gamer;

    public Equip(Gamer gamer) {
        this.gamer = gamer;
    }
    /**
     * 获取目前的装备
     *
     * @return
     */
    @Override
    public String getEquip() {
        return gamer.getEquip();
    }

    /**
     * 获取目前身上装备的价格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return gamer.getPrice();
    }
}

具体装饰器“法师权杖”

public class Truncheon extends Equip {
    public Truncheon(Gamer gamer) {
        super(gamer);
    }

    /**
     * 获取目前的装备
     *
     * @return
     */
    @Override
    public String getEquip() {
        return super.getEquip()+",法师权杖";
    }

    /**
     * 获取目前身上装备的价格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return super.getPrice()+50;
    }
}

具体装饰器“魔法斗篷”

public class Cloak extends Equip {
    public Cloak(Gamer gamer) {
        super(gamer);
    }

    /**
     * 获取目前的装备
     *
     * @return
     */
    @Override
    public String getEquip() {
        return super.getEquip()+",魔法斗篷";
    }

    /**
     * 获取目前身上装备的价格
     *
     * @return
     */
    @Override
    public int getPrice() {
        return super.getPrice()+80;
    }
}

计算装备价格

//创建一个法师玩家
Gamer gamer = new MasterGamer();
//给法师玩家装备法师权杖
gamer = new Truncheon(gamer);
//给法师玩家装备魔法斗篷
gamer = new Cloak(gamer);
System.out.println("当前装备:"+gamer.getEquip()+"\n装备总价值:"+gamer.getPrice());

输出结果

当前装备:大裤衩,法师权杖,魔法斗篷
装备总价值:135

对比

上面例子比较简单,传统继承实现和装饰器模式实现区别不是很明显,但仔细思考还是会发现一些区别:

  • 传统继承实现不自由,没有“组件化”特性。玩家的装备是可以随意组合,随意拆卸的,而这种特性对于继承来说只能通过各种各样的子类组合来实现。就像上面的例子,装备“法师权杖”和“魔法斗篷”需要在拥有“法师权杖”的基础上再去继承。
  • 装饰器模式实现,使得附属属性和主体分开,而又不单独存在(Equip类里面声明了Gamer对象)。装备和玩家是分开的,可以给玩家单独装备任何装备,也可以随意卸下装备。

总结

这种设计模式下不仅可以扩展一个类的功能,也可以动态增加功能,动态撤销。但缺点就是多层装饰使用起来相对比较复杂。本质是将具体功能职责划分(例如区分核心组件以及附加属性职责)减少子类直接继承父类的耦合性。



你可以在这里获取相关代码:设计模式-Decorator模式

原文地址:https://www.cnblogs.com/xuxiaojian/p/11468734.html

时间: 2024-10-05 22:21:24

设计模式-Decorator模式的相关文章

Design Pattern 设计模式 Decorator 装饰者模式

1 设计一个基类 2 继承这个基类,并包含这个基类的一个对象 3 创建继承类的时候,初始化这个基类,因为是基类指针,所以可以是所有基类的衍生类对象,那么就可以叠加任意多个衍生类对象了. 关键是在衍生类中包含一个基类对象,然后有了继承和包含两重关系,可以使得一个类一个类对象叠加,达到装饰目的. 等于是创建了一个对象指针链表,一个一个对象发挥其相应的作用. 下面程序装饰一个桌子,同时包含释放内存的处理. 关键要知道基类的析构函数必须使用虚函数,为什么? 1 如果基类不是析构函数,那么如果衍生类中包含

设计模式(十二)Decorator模式

Decorator模式就是不断地为对象添加装饰的设计模式.以蛋糕为例,程序中的对象就相当于蛋糕,然后像不断地装饰蛋糕一样地不断地对其增加功能,它就变成了使用目的更加明确的对象. 首先看示例程序的类图. 然后看示例程序代码. 1 package bigjunoba.bjtu.decorator; 2 3 public abstract class Display { 4 5 public abstract int getColumns(); 6 public abstract int getRow

浅谈设计模式之八——Decorator模式

先上uml图: 意图:动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. uml解析:装饰者模式又名包装器,顾名思义就是给某个对象添加一些功能,而不是给整个类添加一些功能.Component跟Decorator是聚合关系,子类ConcreteDecoratorA和ConcreteDecoratorB实现具体对Component的修饰. 下面给出可执行的示例代码: Decorator.h #pragma once #include <iostream>

[C++设计模式] decorator 装饰者模式

<head first>中 的例子:咖啡店有各种咖啡饮料,可以往咖啡里面加各种调料变成另一种饮料,如果使用继承的方式来为每一种饮料设计一个类,代码的复杂度很容易膨胀,而且会继承父类的所有特性,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性:同时,又掉入了另一个陷阱,随着扩展功能的增多,子类也会增多,各种子类的组合,就会导致类的膨胀,最后,就会被淹没在类的海洋. 这时大神们就发明了装饰者模式,在不修改现在有接口和实现类的基础上实现功能或者状态的添加. decorator(装饰者模式):

java设计模式 模板方法模式Template Method

设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样.项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因.

设计模式组合模式(Composite)精华

23种子GOF设计模式一般分为三类:创建模式.结构模型.行为模式. 创建模式抽象的实例,他们帮助如何创建一个系统独立.这是一个这些对象和陈述的组合. 创建使用继承类的类架构更改实例.的对象类型模型的建立也将委托实例化一个对象. 创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些详细的类的信息封装起来.第二,它们隐藏了这些类的实例是怎样被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此.创建型模式在什么被创建.谁创建它,它是怎样被创建的,以及何时创建这些方

设计模式--备忘录模式(Memento)

什么是备忘录模式? 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样就可以将以后的对象状态恢复到先前保存的状态. 我们在编程的时候,经常需要保存对象的中间状态,当需要的时候,可以恢复到这个状态.比如,我们使用Eclipse进行编程时,假如编写失误(例如不小心误删除了几行代码),我们希望返回删除前的状态,便可以使用Ctrl+Z来进行返回.这时我们便可以使用备忘录模式来实现. 代码示例: 代码演示了一个单状态单备份的例子,逻辑非常简单:Originator类中的sta

24天学会设计模式----门面模式(外观模式)

一.门面模式 1.定义 GOF<设计模式>一书对Facade模式是这样描述的: 为子系统中的一组接口提供一个统一接口.Facade模式定义了一个更高层的接口,使子系统更加容易使用. 2.结构 门面角色:客户端可以调用这个角色的方法.此角色知道子系统的功能和责任.在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统中去. 子系统角色:可以同时有一个或者多个子系统.每一个子系统都不是一个单独的类,而是一个类的集合.每个子系统都可以被客户端直接调用,或者被门面角色调用. 3.适用性 (1

设计模式 - 装修模式

概述 23种设计模式之一,英文叫Decorator Pattern,又叫装饰者模式.装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 装饰模式的特点 (1) 装饰对象和真实对象有相同的接口.这样客户端对象就能以和真实对象相同的方式和装饰对象交互. (2) 装饰对象包含一个真实对象的引用(reference) (3) 装饰对象接受所有来自客户端的请求.它把这些请求转发给真实的对象. (4) 装饰对象可以在转发这些请求以