zoukankan      html  css  js  c++  java
  • 设计模式 – Decorator – 装饰模式[转]

    “装饰模式(Decorator)”又名“包装模式(Wrapper)”,通常用来灵活地扩充对象的功能
    在此之前我们可以通过类的继承来扩充父类的功能,但这种继承方式缺乏灵活性,并且会导到子类数量的快速膨胀。恰当地使用装饰模式我们会轻松实现在控制子类数量的基础上,灵活地实现对象功能的扩展。装饰模式比类的继承更灵活。

    例子:
    1、墙上挂画(Terrylee的例子):一个画可以挂在墙上,但通常我们会把这张画镶上画框,蒙上玻璃,然后再挂在墙上。这里的画框和玻璃就是对画的装饰,装饰后成为一个物体,后来实际挂在墙上的是画框。

    2、“小猪逃命”游戏:一只小猪和一只灰狼,小猪最多5条命,灰狼每咬到小猪一次,小猪就要少一条命,小猪的任务是要逃过灰狼的追咬到猪栏。在逃的过程中小猪可以吃到三种苹果,吃“红苹果”可以给小猪加上保护罩,吃“绿苹果”可以加快小猪奔跑速度,吃“黄苹果”可以使猪趟着水跑。小猪如果吃多种苹果的话,小猪可以拥有多种苹果提供的功能。
        这个例子如果用类的继承来实现的话那可就麻烦了,你需要为小猪派生3*2*1=6个子类(有保护罩的小猪,奔跑速度加快的小猪,会趟水的小猪,既有保护罩又会趟水的小猪,奔跑速度快且会趟水的小猪,有保护罩且奔跑速度快的小猪,有保护罩、奔跑速度快且会趟水的小猪),当小猪吃到不同的苹果,你就把小猪换成相应的子类实例(好麻烦)。如果有四种苹果的话那你要为小猪派生4*3*2*1=24个子类,如果有五种苹果......“子类复子类,子类何其多”。
        如果使用装饰模式的那就不用派生诸多子类了,当小猪每吃到一个苹果,我们就用装饰模式给小猪加一个动态增加一个新功能即可。

    结构图:

    抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象和抽象装饰器。
    具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。
    抽象装饰(Decorator)角色:持有一个构件(Component)对象的实例,以用来对它进行装饰,并定义一个与抽象构件接口一致的接口。
    具体装饰(Concrete Decorator)角色:负责给构件对象"加上"附加的功能。

    结构图代码:
        //抽象构件,定义了具体构件和抽象装饰要实现的方法
    interface Component
        {
            void Operation();
        }
        //定义具体构件
    class ConcreteComponent : Component
        {
            public void Operation()
            {
                Console.WriteLine("ConcreteComponent Operation");
            }
        }
        //定义抽象装饰者。抽象装饰者也实现了抽象构件的接口
    abstract class Decorator : Component
        {
            //把一个抽象构件作为抽象装饰的成员变量。
    protected Component comp;
           //在抽象装饰者的构造函数中为抽象构件初始化。
    public Decorator(Component c)
            {
                this.comp = c;
            }
           //还未实现的接口的方法。
    public abstract void Operation();
        }
        //具体装饰者A,继承自抽象装饰。
    class ConcreteDecoratorA : Decorator
        {
            private string addedState; //具体装饰者中新增的成员变量
            public ConcreteDecoratorA(Component c) : base(c) { }
            public string AddedState //具体装饰者中新增的属性
            {
                set
                {
                    addedState = value;
                }
            }
           //具体装饰者实现了接口中定义的方法
    public override void Operation()
            {
    comp.Operation();    //可以调用原构件对象的Operation方法。
    Console.WriteLine("ConcreteDecoratorA Operation {0}",addedState);
            }
        }
        //具体装饰者B,继承自抽象装饰。
    class ConcreteDecoratorB : Decorator
        {
            public ConcreteDecoratorB(Component c) : base(c) { }
            public override void Operation()
            {
    comp.Operation(); //可以调用原构件对象的Operation方法。
    Console.WriteLine("ConcreteDecoratorB Operation ");
            }
           // 具体装饰者实现了接口中定义的方法
    public void AddedBehavior()
            {
                Console.WriteLine("This is Added Behavior");
            }
        }
    class Client
        {
            public static void Main()
            {
       //原生的具体构件
                ConcreteComponent cc = new ConcreteComponent();
                cc.Operation();
    //把原生的具体构件用具体装饰者A进行一次包装
                ConcreteDecoratorA cda = new ConcreteDecoratorA(cc);
                cda.AddedState = "Decorator OK ";
                cda.Operation();
        //把原生的具体构件用具体装饰者B进行一次包装
                ConcreteDecoratorB cdb = new ConcreteDecoratorB(cc);
                cdb.AddedBehavior();
                cdb.Operation();
    //把被A包装完的具体构件再用用具体装饰者B进行二次包装
                ConcreteDecoratorB cdbcda = new ConcreteDecoratorB(cda);
                cdbcda.Operation();
            }
        }
        运行结果

    说明:
    Decorator与Component之间既是Is a...的继承关系,又是Has a...的组合关系。使用具体装饰类(ConcreteDecorator)来装饰具体构件对象(ConcreteComponent),装饰完的对象依旧是个Component类型。
        Decorator模式解决的是类的功能的多向扩展,而不是单纯的类的继承。
        Decorator模式提供了比继承更灵活的功能扩展,通过使用不同具体装饰对构件对象的排列组合地包装,能够不同功能的组合。

    小猪逃命游戏示意代码:
        //抽象构件,小猪和装饰者的共同抽象接口
    interface IUnit
        {
            int Count { get;} //属性,取出小猪现有几条命
            void move();       //方法,小猪跑的方法
            void attacked(); //方法,小猪被攻击的方法
        }
        //具体构件,小猪类
    class Pig : IUnit
        {
            private int pigCounts = 5;   //一共有5条命
            public int Count
            {
                get
                {
                    return pigCounts;
                }
            }
            public void move()
            {
                Console.WriteLine("The Pig Is Moving......");
            }
            public void attacked()
            {
    pigCounts--; //小猪受到攻击后,减一条命。
                Console.WriteLine("The Pig Count Is :{0}", pigCounts); //显示小猪还剩下几条命
            }
        }
        //抽象装饰类,用来装饰小猪的抽象类
    abstract class PigDecorator : IUnit
        {
    protected IUnit pig;   //小猪作为装饰类的成员变量
            public PigDecorator(IUnit iu) //在构造函数中为成员变量初始化
            {
                pig = iu;
            }
            public int Count
            {
                get
                {
                    return pig.Count;
                }
            }
            public abstract void move();
            public abstract void attacked();
        }
        //给小猪加上保护罩
    class ProtectedPig : PigDecorator
        {
            public ProtectedPig(IUnit u)
                : base(u)
            {
            }
            public override void move()
            {
    pig.move(); //调用小猪跑的方法。让小猪跑
            }
            public override void attacked()
            {
    //重写小猪被攻击的方法,这里被攻击后生命值不减少。直接显示小猪剩的命。
                Console.WriteLine("The Pig Count Is :{0}", pig.Count);
            }
        }
        //让小猪跑快的装饰器
    class FasterPig : PigDecorator
        {
            public FasterPig(IUnit u)
                : base(u)
            {
            }
            public override void move()
            {
    //重写小猪跑的方法,让它跑得更快。
                Console.WriteLine("The Pig Is Moving Faster Now......");
            }
            public override void attacked()
            {
    pig.attacked(); //当小猪被攻击时,调用小猪被攻击的方法。
            }
        }
        //让小猪会游泳的装饰器
    class SwimPig : PigDecorator
        {
            public SwimPig(IUnit u)
                : base(u)
            {
            }
            public override void move()
            {
                pig.move(); //调用小猪跑的方法。
            }

            public override void attacked()
            {
                pig.attacked(); //调用小猪被攻击的方法
            }
    //给小猪加上会游泳的功能
            public void swim()
            {
                Console.WriteLine("The Pig Can Swim Now ......");
            }
        }
        //红苹果类
    class RedApple
        {
            public ProtectedPig change(IUnit u)
            {
       //用保护罩装饰器来包装小猪。
    ProtectedPig p = new ProtectedPig(u);
                return p;
            }
        }
        //绿苹果
    class GreenApple
        {
            public FasterPig change(IUnit u)
            {
    //让跑快的装饰器来包装小猪
    FasterPig p = new FasterPig(u);
                return p;
            }
        }
        //黄苹果
    class YellowApple
        {
            //用游泳的装饰器来包装小猪
            public SwimPig change(IUnit u)
            {
    SwimPig p = new SwimPig(u);
                return p;
            }
        }
        //灰狼类
    class Monster
        {
    //攻击小猪的方法
            public void attack(IUnit u)
            {
    u.attacked(); //调用小猪被攻击的方法。
            }
        }
    class Client
        {
            public static void Main(string[] args)
            {
                IUnit pig1 = new Pig();//一只原生的小猪
                Monster m = new Monster();  //一只灰狼
                pig1.move(); //小猪开始跑
               //灰狼攻击小猪,调用小猪被攻击的方法,小猪生命减1并显示剩余的生命。
                m.attack(pig1);
                RedApple r = new RedApple();   //出现一只红苹果
                pig1 = r.change(pig1); //小猪吃到红苹果,红苹果把小猪用“保护罩”装饰成“受保护的小猪”
                pig1.move();
                m.attack(pig1); //此时灰狼再咬小猪的时候,发现小猪由于已经被“保护罩”装饰,并未减少生命力
                GreenApple g = new GreenApple();    //出现一只绿苹果
                pig1 = g.change(pig1); //有“保护罩”的小猪又吃了一个绿苹果,此时小猪既有“保护罩”装饰,又有“快速奔跑”装饰。
                pig1.move(); //显示小猪正在快速奔跑
                m.attack(pig1); //小猪受到攻击,生命力仍不减少。
                YellowApple y = new YellowApple();//出现一只黄苹果
                pig1 = y.change(pig1); //“保护罩”“快速奔跑”的小猪又加上了“会游泳”这个包装。
                ((SwimPig)pig1).move();
                ((SwimPig)pig1).swim();  //小猪在游泳
                m.attack(pig1); //小猪受到攻击生命力仍不减
            }
        }
        Decorator模式采用对象组合而非继承的手法,实现了在运行时动态的扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。同时它很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。(车延禄)

     

    DotNet中的例子:
        缓冲流(BufferedStream)

        EnterpriseLibrary中的CommandWrapper

  • 相关阅读:
    Android 按键消息处理Android 按键消息处理
    objcopy
    SQLite多线程读写实践及常见问题总结
    android动画坐标定义
    Android动画效果translate、scale、alpha、rotate
    Android公共库(缓存 下拉ListView 下载管理Pro 静默安装 root运行 Java公共类)
    Flatten Binary Tree to Linked List
    Distinct Subsequences
    Populating Next Right Pointers in Each Node II
    Populating Next Right Pointers in Each Node
  • 原文地址:https://www.cnblogs.com/a311300/p/2062339.html
Copyright © 2011-2022 走看看