场景出发

假设存在如下游戏场景:

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)的更多相关文章

  1. 设计模式(一):“穿越火线”中的“策略模式”(Strategy Pattern)

    在前段时间呢陆陆续续的更新了一系列关于重构的文章.在重构我们既有的代码时,往往会用到设计模式.在之前重构系列的博客中,我们在重构时用到了“工厂模式”.“策略模式”.“状态模式”等.当然在重构时,有的地 ...

  2. 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)

    原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...

  3. 反馈法学习设计模式(一)——策略模式Strategy Pattern

    简介(Introduction) 之前学习Java8实战时,遇到一个很好的策略模式示例.便想着借着这个示例结合反馈式的方法来,学习策略设计模式,也以便后面反复琢磨学习. 首先我们通过练习,逐步写出符合 ...

  4. 设计模式 - 策略模式(Strategy Pattern) 具体解释

    策略模式(Strategy Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26577879 本文版权全 ...

  5. HeadFirst设计模式读书笔记(1)-策略模式(Strategy Pattern)

    策略模式(Strategy Pattern): 定义了了算法簇,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户端. 第一个设计原则:找出应用中可能需要变化之处,把他们独立 ...

  6. 8.6 GOF设计模式四: 策略模式… Strategy Pattern

    策略模式… Strategy Pattern  在POS系统中,有时需要实行价格优惠, 该如何处理?  对普通客户或新客户报全价  对老客户统一折扣5%  对大客户统一折扣10%  注:课件 ...

  7. 二十四种设计模式:策略模式(Strategy Pattern)

    策略模式(Strategy Pattern) 介绍定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法的变化可独立于使用它的客户. 示例有一个Message实体类,对它的操作有 ...

  8. 乐在其中设计模式(C#) - 中介者模式(Mediator Pattern)

    原文:乐在其中设计模式(C#) - 中介者模式(Mediator Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 中介者模式(Mediator Pattern) 作者:weba ...

  9. 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern)

    原文:乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) 作者:weba ...

随机推荐

  1. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #9 RT Group Scheduling 与RT Throttling

    HACK #9 RT Group Scheduling 与RT Throttling 本节介绍对实时进程所使用的CPU时间进行限制的功能RT Group Scheduling和RT Throttlin ...

  2. sql多表更新使用别名(小技巧)

    update     A set     A.CityRegionID=B.ParentID,     A.CityName=(select RegionName from Common_Region ...

  3. PHP-fpm启动时 出现 PHP Warning: PHP Startup: Invalid library (maybe not a PHP library) 'fileinfo.so' in Unknown on line 0

    出现该问题的原因之一是: 在编译PHP时启用了fileinfo扩展(内置),但同时在php.ini文件中添加了: extension=fileinfo.so 去掉或注释之后,重启php-fpm,警告消 ...

  4. 并发包学习(三)-AbstractQueuedSynchronizer总结

    J.U.C学习的第二篇AQS.AQS在Java并发包中的重要性,毋庸置疑,所以单独拿出来理一理.本文参考总结自<Java并发编程的艺术>第五章第二节队列同步器. 什么是AbstractQu ...

  5. mybatis一对多关联查询+pagehelper->分页错误

    mybatis一对多关联查询+pagehelper->分页错误. 现象: 网上其他人遇到的类似问题:https://segmentfault.com/q/1010000009692585 解决: ...

  6. KVC & KVO 入门

    KVC: 简介: 全称 Key-Value Coding .KVC是一种间接访问对象属性(用字符串表征)的机制,而不是直接调用对象的accessor(setter/getter)方法或是直接访问成员对 ...

  7. C++指针的长度

    每台计算机都有字长,指明指针数据的标称大小----来自深入理解计算机系统 每台计算机的字长指明了它的虚拟空间大小.比如32位的机器,虚拟空间地址为0~2^w-1程序最多访问2^w个字节 对于32位程序 ...

  8. php在线编辑本地文件方法共享

    public function testfile() { $cfile='F:\phpStudy\WWW\thinkphp5practise\NNWinLoseConfig.ini'; $cfileh ...

  9. javascript instanceof,typeof的区别

    区分string 与 String的区别 为什么结果会是false呢? <script type="text/javascript"> var aColors = [& ...

  10. VS Code 界面语言设置

    首先Ctrl+shift+p打开命令面板. 输入配置显示语言 回车 更改locale即可更改页面显语言(更改后需重启软件). 目前支持如下语言 Display Language Locale Engl ...