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 ...
随机推荐
- JavaScript之深拷贝&浅拷贝
深拷贝&浅拷贝,说起来都明白,但是说不出所以然.今天就系统的整理下思绪,一点点的将其分析出所以然 废话不多说 浅拷贝 简单的说就是一个值引用,学生时代接触过编程的人都应该了解过指针,浅拷贝可以 ...
- Wasserstein距离 和 Lipschitz连续
EMD(earth mover distance)距离: 在计算机科学与技术中,地球移动距离(EMD)是一种在D区域两个概率分布距离的度量,就是被熟知的Wasserstein度量标准.不正式的说,如果 ...
- eclipse自动生成.apt_generated、factory path
- mpg123解码相关
int attribute_align_arg mpg123_decode(mpg123_handle *mh, const unsigned char *inmemory, size_t inmem ...
- log.error(msg)和log.error(msg,e)的显示区别
log.error(msg): [2017-10-18 11:31:07,652] [Thread-7] (CmsCtlDataUploadFileExchange.java:50) ERROR co ...
- python之name binding
[python之name binding] 1. 名字 名字是对一个对象的称呼,一个对象可以只有一个名字,也可以没有名字或取多个名字.但对象自己却不知道有多少名字,叫什么,只有名字本身知道它所指向 ...
- shell中的字符串操作和数学运算
字符串操作 变量赋值: 说明:变量值可以用单引号.双引号.或者不加任何引号来赋值给变量 变量名="变量值" 变量名='变量值' 变量名=变量值 例如:str="hel ...
- String和CharSequence
String 是java中的字符串,它继承于CharSequence. String类所包含的API接口非常多.为了便于今后的使用,我对String的API进行了分类,并都给出的演示程序. Strin ...
- ConcurrentHashMap的简单理解
一.效率低下的HashTable容器HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下.因为当一个线程访问HashTable的同 ...
- [Selenium]Release in dragAndDrop doesn't work after i update the version of Selenium to 2.45.0
在升级Selenium的版本之前,写了一段拖拽的代码,Drag and Drop 都好使的, 但是,将Selenium的版本升级到2.45.0之后,图标拖拽可以成功,释放不生效. 试了N多种解决方案都 ...