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

场景出发html

假设存在以下游戏场景:算法

1:角色能够装备木剑,铁剑,魔剑3种装备,分别对怪物形成20HP,50HP,100HP伤害(未佩戴装备则没法攻击);ide

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

不假思索地我会写出以下的代码:3d

 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

相信不止我一我的会这样写,由于它能快速的"完美的"实现上述功能code

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

策略者模式对象

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

将上述的场景经过策略者模式来解决,代码以下接口

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 

相关文章
相关标签/搜索