場景出發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 }
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 }
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 }
相信不止我一我的會這樣寫,由於它能快速的"完美的"實現上述功能code
回過頭來再仔細觀察這段代碼,就感受像在看一段"直腸子",全部的邏輯算法都集中到了一個管道上,只要有需求或邏輯上的的變化,那麼就得直接去修改業務類htm
策略者模式對象
其實不少時候咱們都會遇到上述這種狀況,一個業務類中存在這種邏輯,多個if...else來判斷選擇邏輯策略,這個時候若是直接寫入業務類,嚴重違背了OCP原則(開放關閉原則:對擴展開放,對修改關閉)blog
將上述的場景經過策略者模式來解決,代碼以下接口
1 /// <summary> 2 /// 武器攻擊的抽象 3 /// </summary> 4 public interface IWeaponStrategy 5 { 6 void WeaponAttack(Monster monster); 7 }
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 }
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 }
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 }
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 }
使用了策略者模式之後,全部的算法邏輯細節變爲依賴抽象,使得只須要在業務類提供一個注入點,就能夠知足需求,哪怕面對之後的擴展如添加新武器,修改武器傷害值等,也不會修改業務類
類圖
這張圖與策略者模式的類圖仍是有點區別的,緣由在策略者模式下,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