装饰模式
Posted 青墨淡潋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了装饰模式相关的知识,希望对你有一定的参考价值。
学习新模式之前先复习一下旧模式:策略+工厂模式的混合实现。
/// <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 除了执行本层装饰之外,还应调用 记录了上一层装饰的类先执行上一层装饰;
如果只需要固定装饰顺序,完全只需要用单向的继承来做就行。
以上是关于装饰模式的主要内容,如果未能解决你的问题,请参考以下文章