c#设计模式之策略者模式(Strategy Pattern)
场景出发
假设存在如下游戏场景:
1:角色可以装备木剑,铁剑,魔剑3种装备,分别对怪物造成20HP,50HP,100HP伤害(未佩戴装备则无法攻击);
2角色可以向怪物攻击,一次攻击后损失角色所佩戴装备的HP伤害,当HP损失完毕后,怪物死亡;
不假思索地我会写出如下的代码:
class Monster
{
public string Name { get; set; }
public int HP { get; set; }
/// <summary>
/// 怪物被攻击后提示
/// </summary>
/// <param name="loss">武器造成的HP伤害损失</param>
public void Warn(int loss)
{
if (HP <= )
{
Console.WriteLine($"怪物{Name}已经死亡");
return;
} HP -= loss; Console.WriteLine($"怪物{Name}受到{loss}HP伤害"); if (HP <= )
{
Console.WriteLine($"怪物{Name}被打死了");
}
}
}
class Role
{
public string Name { get; set; }
public string Weapon { get; set; }
/// <summary>
/// 武器攻击
/// </summary>
/// <param name="monster">攻击的怪物对象</param>
public void Attack(Monster monster)
{
if (Weapon == "WoodenSword")
{
Console.WriteLine($"{Name}用木剑攻击了{monster.Name}");
monster.Warn();
} else if (Weapon == "IronSword")
{
Console.WriteLine($"{Name}用铁剑攻击了{monster.Name}");
monster.Warn();
}
else if (Weapon == "MagicSword")
{
Console.WriteLine($"{Name}用魔剑攻击了{monster.Name}");
monster.Warn();
}
else
{
Console.WriteLine($"{Name}没有武器,无法攻击");
}
}
}
class Program
{
static void Main(string[] args)
{
var monster = new Monster()
{
Name = "沼泽首领",
HP =
};
var role = new Role()
{
Name = "狂战士",
Weapon="IronSword"
};
role.Attack(monster);
role.Weapon = "WoodenSword";
role.Attack(monster);
role.Weapon = "MagicSword";
role.Attack(monster); Console.ReadKey();
}
}
相信不止我一个人会这样写,因为它能快速的"完美的"实现上述功能
回过头来再仔细观察这段代码,就感觉像在看一段"直肠子",所有的逻辑算法都集中到了一个管道上,只要有需求或逻辑上的的变化,那么就得直接去修改业务类
策略者模式
其实很多时候我们都会遇到上述这种情况,一个业务类中存在这种逻辑,多个if...else来判断选择逻辑策略,这个时候如果直接写入业务类,严重违背了OCP原则(开放关闭原则:对扩展开放,对修改关闭)
将上述的场景通过策略者模式来解决,代码如下
/// <summary>
/// 武器攻击的抽象
/// </summary>
public interface IWeaponStrategy
{
void WeaponAttack(Monster monster);
}
public class WoodenSwordStrategy : IWeaponStrategy
{
public void WeaponAttack(Monster monster)
{
Console.WriteLine("木剑攻击");
monster.Warn();
}
}
public class IronSwordStrategy : IWeaponStrategy
{
public void WeaponAttack(Monster monster)
{
Console.WriteLine("铁剑攻击");
monster.Warn();
}
} public class MagicSwordStrategy : IWeaponStrategy
{
public void WeaponAttack(Monster monster)
{
Console.WriteLine("魔剑攻击");
monster.Warn();
}
}
public class Monster
{
public string Name { get; set; }
public int HP { get; set; } /// <summary>
/// 怪物被攻击后提示
/// </summary>
/// <param name="loss">武器造成的HP伤害损失</param>
public void Warn(int loss)
{
if (HP <= )
{
Console.WriteLine($"怪物{Name}已经死亡");
return;
} HP -= loss; Console.WriteLine($"怪物{Name}受到{loss}HP伤害"); if (HP <= )
{
Console.WriteLine($"怪物{Name}被打死了");
}
}
}
class Role
{
public string Name { get; set; }
public IWeaponStrategy Weapon { get; set; }
public void Attack(Monster monster)
{
Weapon.WeaponAttack(monster);
}
}
class Program
{
static void Main(string[] args)
{
var monster = new Monster()
{
Name = "沼泽首领",
HP =
};
var role = new Role()
{
Name = "狂战士",
Weapon=new IronSwordStrategy()
};
role.Attack(monster);
role.Weapon = new WoodenSwordStrategy();
role.Attack(monster);
role.Weapon = new MagicSwordStrategy();
role.Attack(monster); Console.ReadLine();
}
}
使用了策略者模式以后,所有的算法逻辑细节变为依赖抽象,使得只需要在业务类提供一个注入点,就可以满足需求,哪怕面对以后的扩展如添加新武器,修改武器伤害值等,也不会修改业务类
类图

这张图与策略者模式的类图还是有点区别的,原因在策略者模式下,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
c#设计模式之策略者模式(Strategy Pattern)的更多相关文章
- 设计模式(一):“穿越火线”中的“策略模式”(Strategy Pattern)
在前段时间呢陆陆续续的更新了一系列关于重构的文章.在重构我们既有的代码时,往往会用到设计模式.在之前重构系列的博客中,我们在重构时用到了“工厂模式”.“策略模式”.“状态模式”等.当然在重构时,有的地 ...
- 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)
原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...
- 反馈法学习设计模式(一)——策略模式Strategy Pattern
简介(Introduction) 之前学习Java8实战时,遇到一个很好的策略模式示例.便想着借着这个示例结合反馈式的方法来,学习策略设计模式,也以便后面反复琢磨学习. 首先我们通过练习,逐步写出符合 ...
- 设计模式 - 策略模式(Strategy Pattern) 具体解释
策略模式(Strategy Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26577879 本文版权全 ...
- HeadFirst设计模式读书笔记(1)-策略模式(Strategy Pattern)
策略模式(Strategy Pattern): 定义了了算法簇,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户端. 第一个设计原则:找出应用中可能需要变化之处,把他们独立 ...
- 8.6 GOF设计模式四: 策略模式… Strategy Pattern
策略模式… Strategy Pattern 在POS系统中,有时需要实行价格优惠, 该如何处理? 对普通客户或新客户报全价 对老客户统一折扣5% 对大客户统一折扣10% 注:课件 ...
- 二十四种设计模式:策略模式(Strategy Pattern)
策略模式(Strategy Pattern) 介绍定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法的变化可独立于使用它的客户. 示例有一个Message实体类,对它的操作有 ...
- 乐在其中设计模式(C#) - 中介者模式(Mediator Pattern)
原文:乐在其中设计模式(C#) - 中介者模式(Mediator Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 中介者模式(Mediator Pattern) 作者:weba ...
- 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern)
原文:乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) 作者:weba ...
随机推荐
- 在线OFFICE方案
Office在线预览及PDF在线预览的实现方式大集合 在线浏览office 文件 在线预览文档openoffice+swfTool 类百度文库文档上传.转换和展示功能项目开源代码 微软的office ...
- WMI获取计算机信息
On Error Resume NextstrComputer = "."strInfo = ""Set objWMIService = GetObject(& ...
- 从LinqPad入门Linq
为什么要学习Linq? 在我们日常开发中,经常需要从数据库中执行各式各样的查询来获取需要的数据.但是如果需要对查询获得的数据进行二次筛选呢?linq就提供了对于可枚举类型(实现IEnumerable接 ...
- 2017面向对象程序设计(Java)第十五周学习总结
上周,老师要求同学们自学应用程序部署,并布置了相关的实验任务.此次实验的目的是掌握Java应用程序的打包操作:了解应用程序存储配置信息的两种方法: 了解Applet小应用程序的开发及应用方法:掌握基于 ...
- IT项目经理岗位职责(转)
一. 项目经理岗位职责 1. 项目经理为整个项目的第一责任人. 2. 项目经理对<质量检查报告>中的所有细则负首要责任. 3. 项目经理必须有效掌控项目开发的各个环节,协助.指导项 ...
- mac下git push避免每次都输入用户名和密码的配置
参考链接:http://www.linuxdiyf.com/linux/18389.html 链接2:https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%8 ...
- golang之数组
1.数组:同一种数据类型的固定长度的序列. 2.数组定义:var a [len]int,例如:var a [5]int 3.长度是数组类型的一部分,因此,var a[5] int 和 var a[10 ...
- 在 macOS 中激活 Astash Professional
Astah Professional v7.2.0-1ff236版安装完毕后,直接用压缩包内的 astah-pro.jar 替换原安装目录内的同名文件(/Applications/astah prof ...
- Zookeeper 源码(七)请求处理
Zookeeper 源码(七)请求处理 以单机启动为例讲解 Zookeeper 是如何处理请求的.先回顾一下单机时的请求处理链. // 单机包含 3 个请求链:PrepRequestProcessor ...
- Java Thread系列(七)死锁
Java Thread系列(七)死锁 当线程需要同时持有多个锁时,有可能产生死锁.考虑如下情形: 线程 A 当前持有互斥所锁 lock1,线程 B 当前持有互斥锁 lock2.接下来,当线程 A 仍然 ...