设计模式:装饰者模式

  设计模式系列目录

  装饰者模式么,在生活中我们是经常接触的。比如像我们这么快节奏的生活,好多都是早上去买煎饼。一般我们会这么说:“来一个粗粮煎饼,加两个鸡蛋加一根肠

或者:“来个山东煎饼,只加土豆丝”等等。“煎饼” 就是这个么个有弹性的对象,面饼是不变的,其它的像鸡蛋,肠什么的者在装饰面饼。这个也是我们编程时的一个设计原则

对扩展开放,对修改关闭。(在最后我会给出C# 和C++ 两种代码示例)

  装饰者模式和“煎饼”差不多,它可以动态地将责任("鸡蛋“、“肠”...)附加到对象(”煎饼“)上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

  我们看一下装饰者模式的类图:

  

看这个类图我们可以总结一下装饰者模式的特点:

 1.被装饰对象和装饰品有相同的接口。这样装饰品和被装饰对象就可以相互交互。

 2.装饰品对象包含一个被装饰对象的引用。

 

让我们做一个煎饼吧:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DecoratorDemo
{
    [Flags]
    public enum BcType
    {
        None = 0,       // 0
        SdCakeType,     // 山东煎饼
        EggType,        // 蛋
        SausageType     // 肠
    }

    public interface IBatterCake
    {
        List<BcType> Type();
        double Coast();
    }

    public class NoneBatterCake : IBatterCake
    {
        public List<BcType> Type()
        {
            return new List<BcType> {BcType.None};
        }

        public double Coast()
        {
            return 0;
        }
    }

    /// <summary>
    /// 山东煎饼
    /// </summary>
    public class SdBatterCake : IBatterCake
    {
        public List<BcType> Type()
        {
            return new List<BcType> {BcType.SdCakeType};
        }

        public double Coast()
        {
            return 3.5;
        }
    }

    /// <summary>
    /// 鸡蛋
    /// </summary>
    public class Egg : IBatterCake
    {
        private readonly IBatterCake _batterCake = new NoneBatterCake();

        public Egg(IBatterCake mMoney)
        {
            _batterCake = mMoney;
        }

        public List<BcType> Type()
        {
            List<BcType> types = _batterCake.Type();
            types.AddRange(new List<BcType>() { BcType.EggType });
            return types;
        }

        public double Coast()
        {
            return 1 + _batterCake.Coast();
        }
    }

    /// <summary>
    /// 肠
    /// </summary>
    public class Sausage : IBatterCake
    {
        private readonly IBatterCake _batterCake = new NoneBatterCake();

        public Sausage(IBatterCake mMoney)
        {
            _batterCake = mMoney;
        }

        public List<BcType> Type()
        {
            List<BcType> types = _batterCake.Type();
            types.AddRange(new List<BcType>() { BcType.SausageType });
            return types;
        }

        public double Coast()
        {
            return 2 + _batterCake.Coast();
        }
    }

    /// <summary>
    /// 计算花费
    /// </summary>
    public class CalculateMoney : IBatterCake
    {
        private readonly IBatterCake _batterCake = new NoneBatterCake();
        public CalculateMoney(IBatterCake mMoney)
        {
            _batterCake = mMoney;
        }

        public List<BcType> Type()
        {
            return new List<BcType> {BcType.None};
        }

        public string Description()
        {
            List<BcType> types = _batterCake.Type();

            int eggs = 0, sausage = 0,battercakies = 0;
            for (int index = 0, count = types.Count(); index < count; index++)
            {
                if (types[index] == BcType.SdCakeType)
                    battercakies++;

                if (types[index] == BcType.EggType)
                    eggs++;

                if (types[index] == BcType.SausageType)
                    sausage++;
            }
            StringBuilder description = new StringBuilder();
            if (battercakies > 0)
                description.Append("煎饼").Append(battercakies).Append("个").Append("\n");

            if (eggs > 0)
                description.Append("鸡蛋").Append(eggs).Append("个").Append("\n");

            if (sausage > 0)
                description.Append("烤肠").Append(sausage).Append("个").Append("\n");

            return description.ToString();
        }

        public double Coast()
        {
            return _batterCake.Coast();
        }
    }

    public class Program
    {
        private static void Main(string[] args)
        {
            // 一个山东煎饼
            IBatterCake sdBatterCake = new SdBatterCake();
            // 一个鸡蛋
            IBatterCake egg1 = new Egg(sdBatterCake);
            // 再来个鸡蛋
            IBatterCake egg2 = new Egg(egg1);
            // 再来个肠
            IBatterCake sausage = new Sausage(egg2);

            CalculateMoney calculateMoney = new CalculateMoney(sausage);

            Console.WriteLine(calculateMoney.Description());
            Console.WriteLine("共花费 : {0}", calculateMoney.Coast());
            Console.ReadLine();
        }
    }
}

 

 

看一下结果:

c++代码:

#include <iostream>
#include <string>
#include <list>

using namespace std;
enum class BcType
{
    None = 0,        // 0
    SdCakeType,        // 山东煎饼
    EggType,        // 蛋
    SausageType        // 肠
};

class IBatterCake
{
public:
    virtual ~IBatterCake() {}
    virtual list<BcType> type() const = 0;
    virtual double coast() const = 0;
};

class NoneBatterCake : public IBatterCake
{
public:
    NoneBatterCake() {}
    virtual ~NoneBatterCake() { }

    virtual list<BcType> type() const override
    {
        return list<BcType>{ BcType::None };
    }

    virtual double coast() const override
    {
        return 0;
    }

};

/// <summary>
/// 山东煎饼
/// </summary>
class SdBatterCake : public IBatterCake
{
public:
    SdBatterCake() {}
    virtual ~SdBatterCake() { }
    virtual list<BcType> type() const override
    {
        return list<BcType>{ BcType::SdCakeType };
    }

    virtual double coast() const override
    {
        return 3.5;
    }
};

/// <summary>
/// 鸡蛋
/// </summary>
class Egg : public IBatterCake
{
public:
    Egg() {}
    Egg(IBatterCake *batter)
    {
        if (m_batter)
            delete m_batter;

        m_batter = batter;
    }

    ~Egg()
    {
        delete m_batter;
    }

    virtual list<BcType> type() const override
    {
        list<BcType> ls = m_batter->type();
        ls.push_back(BcType::EggType);

        return ls;
    }

    virtual double coast() const override
    {
        return 3.5 + m_batter->coast();
    }

private:
    IBatterCake *m_batter = new NoneBatterCake();
};

/// <summary>
/// 肠
/// </summary>
class Sausage: public IBatterCake
{
public:
    Sausage() {}
    Sausage(IBatterCake *batter)
    {
        if (m_batter)
            delete m_batter;

        m_batter = batter;
    }

    ~Sausage()
    {
        delete m_batter;
    }

    virtual list<BcType> type() const override
    {
        list<BcType> ls = m_batter->type();
        ls.push_back(BcType::SausageType);

        return ls;
    }

    virtual double coast() const override
    {
        return 2 + m_batter->coast();
    }

private:
    IBatterCake *m_batter = new NoneBatterCake();
};

/// <summary>
/// 计算花费
/// </summary>
class CalculateMoney : public IBatterCake
{
public:
    CalculateMoney(IBatterCake *batter)
    {
        if (m_batter)
            delete m_batter;

        m_batter = batter;
    }
    ~CalculateMoney()
    {
        delete m_batter;
    }

    virtual list<BcType> type() const override
    {
        return list<BcType>{ BcType::None };
    }

    string description()
    {
        list<BcType> types = m_batter->type();

        int eggs = 0, sausage = 0, battercakies = 0;

        for (const BcType &type : types) {
            if (type == BcType::SdCakeType)
                battercakies++;

            if (type == BcType::EggType)
                eggs++;

            if (type == BcType::SausageType)
                sausage++;
        }

        string description;
        if (battercakies > 0)
            description.append("煎饼").append(std::to_string(battercakies)).append("个\n");

        if (eggs > 0)
            description.append("加").append(std::to_string(eggs)).append("个鸡蛋\n");

        if (sausage > 0)
            description.append("加").append(std::to_string(sausage)).append("个烤肠\n");

        return description;
    }

    virtual double coast() const override
    {
        return m_batter->coast();
    }
private:
    IBatterCake *m_batter = new NoneBatterCake();
};

int main()
{
    IBatterCake *sdBatterCake = new SdBatterCake();

    IBatterCake *egg1 = new Egg(sdBatterCake);

    IBatterCake *egg2 = new Egg(egg1);

    IBatterCake *sausage = new Sausage(egg2);

    CalculateMoney *calculateMoney = new CalculateMoney(sausage);
    cout << calculateMoney->description();

    delete calculateMoney;
    cin.get();
    return 0;
}

View Code

 

结果是一样的

 

 

以下情况使用Decorator模式

1. 需要扩展一个类的功能,或给一个类添加附加职责。

2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。

3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

时间: 2024-09-21 08:46:09

设计模式:装饰者模式的相关文章

[Head First设计模式]山西面馆中的设计模式——装饰者模式

引言 在山西面馆吃鸡蛋面的时候突然想起装饰者这个模式,觉得面馆这个场景跟书中的星巴兹咖啡的场景很像,边吃边思考装饰者模式.这里也就依葫芦画瓢,换汤不换药的用装饰者模式来模拟一碗鸡蛋面是怎么出来的吧.吃货有吃货的方式来理解......这里先将书中讲到的例子放在前面,理论的东西,讲的还是比较具体的,只是觉得咖啡的例子不是太好理解,lz很土,几乎没喝过咖啡,不知道什么摩卡啊......,还是中国特色的例子更好理解. 为什么学设计模式? 答:觉得会设计模式的人,不仅仅是码农,更像艺术家! 为什么现在学设

PHP设计模式——装饰器模式

声明:本系列博客参考资料<大话设计模式>,作者程杰.         装饰器模式又叫装饰者模式.装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象.         UML类图:                  角色:        组件对象的接口:可以给这些对象动态的添加职责        所有装饰器的父类:需要定义一个与组件接口一致的接口,并持有一个Component对象,该对象其实就是被装饰的对象.      

PHP设计模式装饰器模式实例

我们在使用面向对象的日常开发过程中,或许会碰见需要对某个方法或者某个对象,添加新的行为.然而常见的做法是,写一个子类继承需要改写的类,然后去重新实现类的方法. 但是装饰器模式(Decorator),可以动态地添加修改类的功能,在使用装饰器模式,仅需在运行时添加一个装饰器对象既可实现,相对与生成子类更加的灵活. 在我们需要改写一个类的时候通常的做法是采用继承的方式来重新方法,如下代码 /*  * 比如我们需要改写一串字符串的样式,采用继承的写法.  */ class Canvas {     fu

设计模式之禅之设计模式-装饰者模式

一:装饰模式的定义        --->动态地给一个对象添加一些额外的职责.就增加功能来说,装饰模式相比生成子类更为灵活.        --->如果大家还记得代理模式,那么很容易看懂这个类图,装饰类的作用也就是一个特殊的代理类.        --->在装饰模式中,必然有一个最基本.最核心.最原始的接口或抽象类充当Component抽象构件 二:装饰模式的角色        ● Component抽象构件                Component是一个接口或者是抽象类,就是定

传统设计模式(三)装饰者模式

说到这个模式的项目实例 虫子也满头疼的 所谓装饰者模式说白了动态将职责附加到对象上.如果你在项目某个场景中需要功能扩展根据基类衍生出非常多的子类,那么装饰者模式无疑是很好的.不过其实在实际的项目中,往往大家不直接衍生子类,而是通过组合的方式,根据逻辑讲各种扩展叠加来,对外公布的只是一个标签一个壳而已. 所以这个章节,虫子就虚构一个实例了.还拿电商来说.点券赠品系统. 背景: 1.所有点券.优惠券.赠品券.积分继承同一个基类 基类券 2.不用种类的券可以混合搭配 3.积分根据不同的场景可以配置不同

简单了解设计模式中的装饰者模式及C++版代码实现_C 语言

由遇到的问题引出的装饰模式 在 OO 设计和开发过程,可能会经常遇到以下的情况:我们需要为一个已经定义好的类添加新的职责(操作),通常的情况我们会给定义一个新类继承自定义好的类,这样会带来一个问题(将在本模式的讨论中给出).通过继承的方式解决这样的情况还带来了系统的复杂性,因为继承的深度会变得很深. 而装饰提供了一种给类增加职责的方法,不是通过继承实现的,而是通过组合. 有关这些内容在讨论中进一步阐述.模式选择装饰模式典型的结构图为: 在 结 构 图 中 , ConcreteComponent

学习JavaScript设计模式之装饰者模式_javascript技巧

有时我们不希望某个类天生就非常庞大,一次性包含许多职责.那么我们就可以使用装饰着模式. 装饰着模式可以动态地给某个对象添加一些额外的职责,从而不影响这个类中派生的其他对象. 装饰着模式将一个对象嵌入另一个对象之中,实际上相当于这个对象被另一个对象包装起来,形成一条包装链. 一.不改动原函数的情况下,给该函数添加些额外的功能 1. 保存原引用 window.onload = function() { console.log(1); }; var _onload = window.onload ||

java设计模式系列之装饰者模式_java

何为装饰者模式 (Decorator)? 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活.一.结构 Component : 定义一个对象接口,可以给这些对象动态地添加职责. interface Component { public void operation(); } ConcreteComponent : 实现 Component 定义的接口. class ConcreteComponent implements Component { @O

[Head First设计模式]云南米线馆中的设计模式——模版方法模式

系列文章 [Head First设计模式]山西面馆中的设计模式--装饰者模式 [Head First设计模式]山西面馆中的设计模式--观察者模式 [Head First设计模式]山西面馆中的设计模式--建造者模式 [Head First设计模式]饺子馆(冬至)中的设计模式--工厂模式 [Head First设计模式]一个人的平安夜--单例模式 [Head First设计模式]抢票中的设计模式--代理模式 [Head First设计模式]面向对象的3特征5原则 [Head First设计模式]鸭子

轻松掌握java装饰者模式_java

定义:在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 特点:     (1) 装饰对象和真实对象有相同的接口.这样客户端对象就能以和真实对象相同的方式和装饰对象交互.     (2) 装饰对象包含一个真实对象的引用(reference)     (3) 装饰对象接受所有来自客户端的请求.它把这些请求转发给真实的对象.     (4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能.这样就确保了在运行时,不用修改给定对象