• c#设计模式之策略者模式(Strategy Pattern)


    场景出发

    假设存在如下游戏场景:

    1:角色可以装备木剑,铁剑,魔剑3种装备,分别对怪物造成20HP,50HP,100HP伤害(未佩戴装备则无法攻击);

    2角色可以向怪物攻击,一次攻击后损失角色所佩戴装备的HP伤害,当HP损失完毕后,怪物死亡;

    不假思索地我会写出如下的代码:

     1   class Monster
     2     {
     3         public string Name { get; set; }
     4         public int HP { get; set; }
     5         /// <summary>
     6         /// 怪物被攻击后提示
     7         /// </summary>
     8         /// <param name="loss">武器造成的HP伤害损失</param>
     9         public void Warn(int loss)
    10         {
    11             if (HP <= 0)
    12             {
    13                 Console.WriteLine($"怪物{Name}已经死亡");
    14                 return;
    15             }
    16 
    17             HP -= loss;
    18 
    19             Console.WriteLine($"怪物{Name}受到{loss}HP伤害");
    20 
    21             if (HP <= 0)
    22             {
    23                 Console.WriteLine($"怪物{Name}被打死了");
    24             }
    25         }
    26     }
    View Code
     1   class Role
     2     {
     3         public string Name { get; set; }
     4         public string Weapon { get; set; }
     5         /// <summary>
     6         /// 武器攻击
     7         /// </summary>
     8         /// <param name="monster">攻击的怪物对象</param>
     9         public void Attack(Monster monster)
    10         {
    11             if (Weapon == "WoodenSword")
    12             {
    13                 Console.WriteLine($"{Name}用木剑攻击了{monster.Name}");
    14                 monster.Warn(25);
    15             }
    16 
    17             else if (Weapon == "IronSword")
    18             {
    19                 Console.WriteLine($"{Name}用铁剑攻击了{monster.Name}");
    20                 monster.Warn(50);
    21             }
    22             else if (Weapon == "MagicSword")
    23             {
    24                 Console.WriteLine($"{Name}用魔剑攻击了{monster.Name}");
    25                 monster.Warn(100);
    26             }
    27             else
    28             {
    29                 Console.WriteLine($"{Name}没有武器,无法攻击");
    30             }
    31         }
    32     }
    View Code
     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             var monster = new Monster()
     6             {
     7                 Name = "沼泽首领",
     8                 HP = 80
     9             };
    10             var role = new Role()
    11             {
    12                 Name = "狂战士",
    13                 Weapon="IronSword"
    14             };
    15             role.Attack(monster);
    16             role.Weapon = "WoodenSword";
    17             role.Attack(monster);
    18             role.Weapon = "MagicSword";
    19             role.Attack(monster);
    20 
    21             Console.ReadKey();
    22         }
    23     }
    View Code

    相信不止我一个人会这样写,因为它能快速的"完美的"实现上述功能

    回过头来再仔细观察这段代码,就感觉像在看一段"直肠子",所有的逻辑算法都集中到了一个管道上,只要有需求或逻辑上的的变化,那么就得直接去修改业务类

    策略者模式

    其实很多时候我们都会遇到上述这种情况,一个业务类中存在这种逻辑,多个if...else来判断选择逻辑策略,这个时候如果直接写入业务类,严重违背了OCP原则(开放关闭原则:对扩展开放,对修改关闭)

    将上述的场景通过策略者模式来解决,代码如下

    1    /// <summary>
    2     /// 武器攻击的抽象
    3     /// </summary>
    4     public interface IWeaponStrategy
    5     {
    6         void WeaponAttack(Monster monster);
    7     }
    View Code
     1     public class WoodenSwordStrategy : IWeaponStrategy
     2     {
     3         public void WeaponAttack(Monster monster)
     4         {
     5             Console.WriteLine("木剑攻击");
     6             monster.Warn(20);
     7         }
     8     }
     9     public class IronSwordStrategy : IWeaponStrategy
    10     {
    11         public void WeaponAttack(Monster monster)
    12         {
    13             Console.WriteLine("铁剑攻击");
    14             monster.Warn(50);
    15         }
    16     }
    17 
    18     public class MagicSwordStrategy : IWeaponStrategy
    19     {
    20         public void WeaponAttack(Monster monster)
    21         {
    22             Console.WriteLine("魔剑攻击");
    23             monster.Warn(100);
    24         }
    25     }
    View Code
     1    public class Monster
     2     {
     3         public string Name { get; set; }
     4         public int HP { get; set; }
     5 
     6         /// <summary>
     7         /// 怪物被攻击后提示
     8         /// </summary>
     9         /// <param name="loss">武器造成的HP伤害损失</param>
    10         public void Warn(int loss)
    11         {
    12             if (HP <= 0)
    13             {
    14                 Console.WriteLine($"怪物{Name}已经死亡");
    15                 return;
    16             }
    17 
    18             HP -= loss;
    19 
    20             Console.WriteLine($"怪物{Name}受到{loss}HP伤害");
    21 
    22             if (HP <= 0)
    23             {
    24                 Console.WriteLine($"怪物{Name}被打死了");
    25             }
    26         }
    27     }
    View Code
    1     class Role
    2     {
    3         public string Name { get; set; }
    4         public IWeaponStrategy Weapon { get; set; }
    5         public void Attack(Monster monster)
    6         {
    7             Weapon.WeaponAttack(monster);
    8         }
    9     }
    View Code
     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             var monster = new Monster()
     6             {
     7                 Name = "沼泽首领",
     8                 HP = 80
     9             };
    10             var role = new Role()
    11             {
    12                 Name = "狂战士",
    13                 Weapon=new IronSwordStrategy()
    14             };
    15             role.Attack(monster);
    16             role.Weapon = new WoodenSwordStrategy();
    17             role.Attack(monster);
    18             role.Weapon = new MagicSwordStrategy();
    19             role.Attack(monster);
    20 
    21             Console.ReadLine();
    22         }
    23     }
    View Code

    使用了策略者模式以后,所有的算法逻辑细节变为依赖抽象,使得只需要在业务类提供一个注入点,就可以满足需求,哪怕面对以后的扩展如添加新武器,修改武器伤害值等,也不会修改业务类

    类图

     这张图与策略者模式的类图还是有点区别的,原因在策略者模式下,Monster这个业务类是没有任何意义的,它仅仅代表一个数据类型参数,可以看作int,而它拥有的具体逻辑+Warn():void,是应该放在策略之中的,所以在策略者模式中有3中角色

    业务角色(Role):具体的业务类,策略抽象的注入点

    策略抽象角色(IWeaponStrategy):策略的抽象,接口或抽象类

    具体策略角色(WoodenSwordStrategy,IronSwordStrategy,MagicSwordStrategy):具体的策略,封装了各种逻辑

    适用场景

    对象存在多个行为或业务,通过if-else来判断选择,这样可以将他们封装在各种策略之中选择

    优缺点

    优点:1代码清晰,相比于大量的if-else,使用策略者模式,使得代码更加的清晰优雅

            2扩展性好:对于添加新的功能,修改逻辑等扩展,使用策略者模式能够很好的支持

    缺点:1增加了程序的复杂程度

            2在各种策略实例的时候,依然存在细节,但是可以通过依赖注入控制反转很好的解决

     出自:博客园-半路独行

     原文地址:https://www.cnblogs.com/banluduxing/p/9170524.html 

     本文出自于http://www.cnblogs.com/banluduxing 转载请注明出处。

     参考文章:http://www.cnblogs.com/leoo2sk/archive/2009/06/17/di-and-ioc.html#3930415

                  http://www.cnblogs.com/zhili/p/StragetyPattern.html 

  • 相关阅读:
    CLR Via
    HTML&XML
    SNS研究
    DotNet&C#
    电子商务
    WCF学习
    SQL
    构架设计
    JS&Ajax
    NHibernate之旅系列文章导航
  • 原文地址:https://www.cnblogs.com/banluduxing/p/9170524.html
Copyright © 2020-2023  润新知