首页 > 代码库 > 装饰模式

装饰模式

  学习新模式之前先复习一下旧模式:策略+工厂模式的混合实现。

    /// <summary>    /// 这里还是采用了抽象类,而不是接口    /// 之前尝试使用接口,但接口在类中并不能当做委托被动态改变    /// 从这里也可以看出接口的用处:作为一种行为,有这种行为的对象都有各自的固定实现,而不会动态改变。    /// 抽象类跟委托方法是可以动态改变的,方便用来设计策略模式    /// 抽象方法必须包含在抽象类中    /// </summary>    public abstract class IAction_Attack         {        public abstract void Attack();    }    public class PL_8 : IAction_Attack    {        public override void Attack()        {            Console.WriteLine("PL-8 Attacks.");        }    }    public class PL_10 : IAction_Attack    {        public override void Attack()        {            Console.WriteLine("PL-10 Attacks.");        }    }    public class CJ_10 : IAction_Attack    {        public override void Attack()        {            Console.WriteLine("CJ-10 Attacks.");        }    }    public class FightPlane : IAction_Attack    {        public IAction_Attack CurrentWeapon { get; set; }        /// <summary>        /// 自身内部采用一个工厂模式生成武器策略;        /// </summary>        /// <param name="command"></param>        public void ReadyToFire(string command)        {            switch(command)            {                case "PL-8":                    CurrentWeapon = new PL_8();                    break;                case "PL-10":                    CurrentWeapon = new PL_10();                    break;                case "CJ-10":                    CurrentWeapon = new CJ_10();                    break;            }        }        public override void Attack()        {            if (CurrentWeapon == null)                Console.WriteLine("No weapon is ready.");            else                CurrentWeapon.Attack();        }    }    public class Program    {        static void Main(string[] args)        {            var J_20 = new FightPlane();            J_20.Attack();            J_20.ReadyToFire("PL-8");            J_20.Attack();            J_20.ReadyToFire("PL-10");            J_20.Attack();            J_20.ReadyToFire("CJ-10");            J_20.Attack();            Console.Read();        }          }

  由于C#没有多重继承,那么继承关系的抽象应该更加谨慎,而不应该将“攻击行为”作为“战斗机”的基类。

  战斗机与导弹之间应该是一种依赖关系,修改:

    public abstract class Missile         {        public abstract void Attack();    }    public class PL_8 : Missile    {        public override void Attack()        {            Console.WriteLine("PL-8 Attacks.");        }    }    public class PL_10 : Missile    {        public override void Attack()        {            Console.WriteLine("PL-10 Attacks.");        }    }    public class CJ_10 : Missile    {        public override void Attack()        {            Console.WriteLine("CJ-10 Attacks.");        }    }    public class FightPlane    {        public Missile CurrentWeapon { get; set; }        /// <summary>        /// 自身内部采用一个工厂模式生成武器策略;        /// </summary>        /// <param name="command"></param>        public void ReadyToFire(string command)        {            switch(command)            {                case "PL-8":                    CurrentWeapon = new PL_8();                    break;                case "PL-10":                    CurrentWeapon = new PL_10();                    break;                case "CJ-10":                    CurrentWeapon = new CJ_10();                    break;            }        }        public void Attack()        {            if (CurrentWeapon == null)                Console.WriteLine("No weapon is ready.");            else                CurrentWeapon.Attack();        }    }    public class Program    {        static void Main(string[] args)        {            var J_20 = new FightPlane();            J_20.Attack();            J_20.ReadyToFire("PL-8");            J_20.Attack();            J_20.ReadyToFire("PL-10");            J_20.Attack();            J_20.ReadyToFire("CJ-10");            J_20.Attack();            Console.Read();        }          }

  以上都是工厂、策略模式的复习,在这个例子上做装饰模式的学习。

 

示例:

  

    public abstract class Missile    {        public abstract void Attack();    }    public class PL_8 : Missile    {        public override void Attack()        {            Console.WriteLine("PL-8 Attacks.");        }    }    public class PL_10 : Missile    {        public override void Attack()        {            Console.WriteLine("PL-10 Attacks.");        }    }    public class CJ_10 : Missile    {        public override void Attack()        {            Console.WriteLine("CJ-10 Attacks.");        }    }    public class FightPlane    {        public Missile CurrentWeapon { get; set; }        /// <summary>        /// 自身内部采用一个工厂模式生成武器策略;        /// </summary>        /// <param name="command"></param>        public void ReadyToFire(string command)        {            switch (command)            {                case "PL-8":                    CurrentWeapon = new PL_8();                    break;                case "PL-10":                    CurrentWeapon = new PL_10();                    break;                case "CJ-10":                    CurrentWeapon = new CJ_10();                    break;            }        }        public void Attack()        {            if (CurrentWeapon == null)                Console.WriteLine("No weapon is ready.");            else                CurrentWeapon.Attack();        }        public virtual void Decorate()        {            Console.WriteLine("PLAF standard decoration.");            }    }    /// <summary>    /// 装饰者:与被装饰者的基类相同,都表示对同一类事物进行装饰    /// </summary>    public class DecoratedFighter : FightPlane    {        /// <summary>        /// 被装饰者        /// 装饰模式的核心:通过动态绑定不同的被装饰者来加载上一层装饰者        /// </summary>        private FightPlane _fighter;        public FightPlane Fighter        {            get            {                return _fighter;            }            set            {                _fighter = value;            }        }        /// <summary>        /// 装饰功能        /// </summary>        public override void Decorate()        {            if (Fighter != null)                Fighter.Decorate();                        }    }    public class LowVisibleFighter : DecoratedFighter    {        public bool IsVisible { get; set; }        public override void Decorate()        {            IsVisible = true;            Console.WriteLine("Low visible decoration.");            base.Decorate();        }    }    public class BlackSilkFighter : DecoratedFighter    {        public override void Decorate()        {            Console.WriteLine("Black silk decoration.");            base.Decorate();        }    }    public class StealthFighter : DecoratedFighter    {        public bool IsStealth { get; set; }        public override void Decorate()        {            Console.WriteLine("Stealth paint decoration.");            base.Decorate();        }        public bool BeingDetect()        {            if (IsStealth == true)                return false;            else                return true;        }    }    public class Program    {        static void Main(string[] args)        {            var Standard_J20 = new FightPlane();            var LowVisible_J20 = new LowVisibleFighter();            LowVisible_J20.Fighter = Standard_J20;            var Stealth_J20 = new StealthFighter();            Stealth_J20.Fighter = LowVisible_J20;            Stealth_J20.Decorate();            Stealth_J20.ReadyToFire("PL-8");            Stealth_J20.Attack();            Stealth_J20.ReadyToFire("PL-10");            Stealth_J20.Attack();            Stealth_J20.ReadyToFire("CJ-10");            Stealth_J20.Attack();            Console.Read();        }    }

UML类图:

技术分享

类图小结:

  1. 整个结构以 FightPlane 为基类,表示为同一类对象,始终保持继承 Decorate 这个行为;

  2. 为了灵活的装饰顺序,装饰子类统一继承装饰基类,而不固定继承顺序,装饰基类 DecoratedFighter 额外聚合了一个基类来记录上一层的装饰类;

  3. 每一层的 Decorate 除了执行本层装饰之外,还应调用 记录了上一层装饰的类先执行上一层装饰;

 

  如果只需要固定装饰顺序,完全只需要用单向的继承来做就行。

装饰模式