策略模式
定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用者,使系统不在担心遇到任何改变,即动态的设定功能。
1. 问题场景
顾客或者用户需要别的东西,或者想要新的功能。功能的改进或者是添加需要我们去改动应用中的代码,我们知道有时候使用继承并不能很好的解决问题,因为对象的行为或者说是功能在子类里不断的改变,让所有的子类都有都有这些行为或是功能是不恰当的。
2. 实例
比如说我们做一个对战游戏中会出各种的的人物,此系统内部设计使用了标准的oo技术,设计了一个人物超类,并让各种人物继承此超类。
public abstract class Role
{
public int HP { get; set; } = 10;
public int MP { get; set; } = 10;
public void attack(Role role) {
role.HP--;
Console.WriteLine("我打了你一下 ! ! !还没有掉蓝 !!!");
}
public abstract void display();
}
public class RoleA:Role
{
public override void display()
{
Console.WriteLine("我是A");
}
}
public class RoleB : Role
{
public override void display()
{
Console.WriteLine("我是B");
}
}
突然有一天,需要角色会使用武器,出现物理攻击和法术攻击等一系列的进攻方式,这样就有一个问题如果我修改攻击方式就会修改全部角色的攻击方式,对代码所作的局部修改,影响的层面可不止是局部。呐,我第一时间想到就是继承我把攻击的方法覆盖掉。
public class RoleA:Role
{
public override void display()
{
Console.WriteLine("我是A");
}
new public void attack(Role role) {
role.HP--;
this.MP--;
Console.WriteLine("我打了你一下 ! ! !掉蓝了 !!!");
}
}
这样攻击代码就是不能重复,但是这样如果产品一直要更新修改攻击模式,我们就陷入了无穷无尽的修改检查覆盖的噩梦中。我又想到如果我把这些多变的功能拿出来做成接口给让他成继承关系我是不是就可以少了检查,但是重复的代码依旧会变多。还是没有解决。
继承并不能很好的解决问题,因为角色攻击行为在子类里不断的变化,并且让所有的子类有这样的攻击行为是不正确的,创建一个攻击接口的方法似乎不错,可是c#接口并不具有实现代码,所以继承接口无法达到代码的复用。这意味着我们必须往下查找在定义此行为的类中修改它。容易造成新的错误。
这样我就想到了一个设计原则:
找出应用中可能需要的变化之处,把他们独立出来,不和不需要变化的代码混在一起
这样的代码的变化引起不经意的后果变少系统变得更有弹性。
第二个设计原则:面向接口编程而不是面向实现编程。
这样角色的攻击行为将被分开放在类中,此类专门提供某行为的接口,这样,角色的类就不再需要知道行为实现的具体细节了。
说到这里就不得不说到接口了,接口是一个“概念”也是C#的interface的构造。我们可以在不涉及interface的情况下“面向接口编程”,其实“面向接口编程”就是“面向超类编程”,通常就是一个抽象或者是一个接口。关键就是利用多态,程序就可针对超类编程,执行时就会执行带真正的行为。不会绑死在超类的行为上。
额 废话有点多,上代码:
public interface AttackBehavior
{
void attack(Role role);
}
public class PhysicalAttack : AttackBehavior
{
public void attack(Role role)
{
role.HP--;
Console.WriteLine("我打了你一下 ! ! !还没有掉蓝 !!!");
}
}
public abstract class Role
{
protected AttackBehavior attackBehavior;
public int HP { get; set; } = 10;
public int MP { get; set; } = 10;
public void attack(Role role) {
attackBehavior.attack(role);
}
public abstract void display();
}
public class RoleA:Role
{
public RoleA(AttackBehavior attack)
{
attackBehavior = attack;
}
public override void display()
{
Console.WriteLine("我是A");
}
}
这样就可以直接在main调用了
static void Main(string[] args)
{
Role roleA = new RoleA();
roleA.Attack();
}
我们封装了行为把 “是一个” 变成 “有一个” 正好符合了另一个设计原则:
多用组合少继承
完
d=====( ̄▽ ̄*)b