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 

相關文章
相關標籤/搜索