zoukankan      html  css  js  c++  java
  • 设计模式:装饰者模式

      设计模式系列目录

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

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

    对扩展开放,对修改关闭。(在最后我会给出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("
    ");
    
                if (eggs > 0)
                    description.Append("鸡蛋").Append(eggs).Append("").Append("
    ");
    
                if (sausage > 0)
                    description.Append("烤肠").Append(sausage).Append("").Append("
    ");
    
                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("");
    
            if (eggs > 0)
                description.append("").append(std::to_string(eggs)).append("个鸡蛋
    ");
    
            if (sausage > 0)
                description.append("").append(std::to_string(sausage)).append("个烤肠
    ");
    
            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. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
  • 相关阅读:
    【算法】CDQ分治 -- 三维偏序 & 动态逆序对
    【题解】ZJOI2007报表统计
    【乱七八糟】兰陵王
    【题解】NOI2017游戏
    【题解】JSOI2010满汉全席
    【题解】NOI2014动物园
    【题解】HNOI2010合唱队
    【题解】SDOI2010地精部落
    cf 843 D Dynamic Shortest Path [最短路+bfs]
    cf 843 B Interactive LowerBound [随机化]
  • 原文地址:https://www.cnblogs.com/li-peng/p/4807761.html
Copyright © 2011-2022 走看看