标签:ogr 可扩展 gif close new console log form 分享图片
场景出发
假设存在如下游戏场景:
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 }
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 }
相信不止我一个人会这样写,因为它能快速的"完美的"实现上述功能
回过头来再仔细观察这段代码,就感觉像在看一段"直肠子",所有的逻辑算法都集中到了一个管道上,只要有需求或逻辑上的的变化,那么就得直接去修改业务类
改进分析
分析上述代码,它严重违背了开闭原则(OCP,Open Closed Principle,即我们的程序是可扩展的,在遇到新的需求或者变化的时候,是不需要对原有类有任何修改的),显然上述代码无法适应新的需求.随便一点需求的变化,就必须去修改具体类,对此我们做出如下简单的修改:
将Weapon抽象出来, 使Role对Weapon的依赖,转为对Weapon抽象的依赖,代码如下
1 public interface IWeaponStrategy 2 { 3 void WeaponAttack(Monster monster); 4 }
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 }
结语
也许结束来的突兀,但是我想表述的东西已经接近尾声,,其实最初我写了很多,什么各种注入的方式介绍,反射加配置文件等,甚至Unity框架的例子我都写了一个,但是真的越写越不痛快,因为这这篇文章越写越多的时候,我脑子里面的东西反而越来越少
依赖注入即控制反转:
起因:客户类或上端)(Role)依赖了服务类(Weapon)的细节(实例);
目的:降低程序耦合度
方式:依赖抽象
延伸:在上端仍有细节(需要实例武器抽象)
本质:一个转移依赖的过程
当你真的理解上述改进的过程,记住了它的本质,你就不会被不同包装的依赖注入所困扰
推荐博客:依赖注入那些事儿
出自:博客园-半路独行
原文地址:https://www.cnblogs.com/banluduxing/p/9185142.html
本文出自于http://www.cnblogs.com/banluduxing 转载请注明出处。
标签:ogr 可扩展 gif close new console log form 分享图片
原文地址:https://www.cnblogs.com/banluduxing/p/9185142.html