举个栗子
小明要设计一个计算器程序,要考虑加减乘除四则运算,对于程序来说,就是把变量放到正确的位置进行计算得出结果。不管是做什么运算,本质都是输入数字,得出结果。相同的是输入数字,不同的是运算符,那么这里就有不同的算法策略👇
设计原则
- 找出应用之中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
- 把变化的部分取出 封装 起来,好让其他部分不受到影响!这样可以应对代码变化,系统更加具有弹性!
- 把会变化的部分取出来并封装起来,方便后续改动或者扩充此部分,而不影响不需要变化的其他部分
- 每个设计模式背后的思想:系统中的某部分改变不会影响其他部分!
- 针对接口编程,而不是针对实现编程
- 让一切具有弹性,运行时动态改变对象的行为!
- 具对象不用实现行为,由接口实现行为,对象不需要知道行为其中的细节
- 把某一行为抽象成接口,具体实现这个行为的类继承该接口
- 针对超类型编程,变量的声明类型是超类型:抽象类或者接口,只要具体实现此超类型的类们,都可用被指派给超类型变量,在声明类时,不用理会后续执行的真正对象类型
解决问题
- 同一类型做不同行为,解决使用继承实现代码 复用 带来的缺陷
- 让代码具有弹性,修改一个行为不影响其他行为也方便添加新行为
- 行为写在(绑死)具体对象类中,需要修改更多代码修改行为或者增减行为,容易bug
针对接口与针对实现区别
针对实现编程:若声明变量 a
为 Add
类型,则必须要具体实现 Add
类型,但其实 Add
是 Operation
的具体实现
Add a = new Add();
a.ExcuteAdd(n1, n2);
针对接口/超类型编程做法:我们知道对象是狗,但是我们不用 Add
来定义,我们用 Operation
进行多态调用!
Operation operation = new Operation();
Operation.Excute();
子类实例化不需要编码,可以在运行时指定具体实现对象,我们不关心实际的子类型是什么,我们只需要知道它可以进行Operation
行为!
a = getOperation();
a.Excute();
优劣势适用场合
优点
- 可以自由切换,动态改变对象的行为
- 避免多重的if…else…判断
- 扩展性良好,简单方便
缺点
- 策略类增多,代码多
- 具体类要知道并决定使用哪个策略类
适用
- 如果在一个系统里面有许多相似的类,区别只在于行为不同,可以使用策略模式动态地让一个类选择多种/一种行为。
- 一个系统需要动态地在几种算法中选择一种,那么每个策略就是一种算法
- 若一个对象有多种行为也不用恰当的模式,这些行为只能用多重的条件选择语句来实现。
注意! 如果一个系统的策略多于4个!就要考虑使用混合模式,解决策略类的膨胀问题!
具体实现
类图
操作接口,Strategy
定义方法,所有实现接口的类都需要重写 doOperation()
Context
是使用了某种策略的类,executeStrategy
是执行某种行为,Context
在配置或者使用策略改变时,行为可以自由变换
C#实现代码
1. 创建接口
IStrategy.cs
interface IStrategy
{
int DoOperation(int num1, int num2);
}
2. 创建实现接口的实体类
OperationAdd.cs
class OperationAdd : IStrategy
{
public int DoOperation(int num1, int num2)
{
//throw new NotImplementedException();
int sum = num2 + num1;
Console.Write("do OperationAdd [做加法运算]: " + num1 + " + " + num2 + " = " + sum + "\n");
return sum;
}
}
OperationSubtract.cs
class OperationSubtract : IStrategy
{
public int DoOperation(int num1, int num2)
{
//throw new NotImplementedException();
int res = num1 - num2;
Console.Write("do OperationSubtract [做减法运算]:" + num1 + " - " + num2 + " = " + res + "\n");
return res;
}
}
OperationMultiply.cs
class OperationMultiply : IStrategy
{
public int DoOperation(int num1, int num2)
{
// 乘法
//throw new NotImplementedException();
int res = num1 * num2;
Console.Write("do OperationMultiply [做乘法运算]:" + num1 + " × " + num2 + " = "+ res + "\n");
return res;
}
}
3. 创建Context类
Context.cs
IStrategy strategy;
public Context(IStrategy strategy)
{
this.strategy = strategy;
}
public int ExecuteStrategy(int num1,int num2)
{
return this.strategy.DoOperation(num1, num2);
}
4. 使用Context来查看当它改变策略 Strategy
时的行为变化
Program.cs
class Program
{
static void Main(string[] args)
{
int num1 = 10;
int num2 = 20;
StrategyContext AddContext = new StrategyContext(new OperationAdd());
int sum = AddContext.ExecuteStrategy(num1, num2);
Console.Write("AddContext ExecuteStrategy Result is:" + sum + "\n\n");
StrategyContext MultiplyContext = new StrategyContext(new OperationMultiply());
int multiply = MultiplyContext.ExecuteStrategy(num1, num2);
Console.Write("MultiplyContext ExecuteStrategy Result is:" + multiply + "\n\n");
StrategyContext SubtractContext = new StrategyContext(new OperationSubtract());
int subtract = SubtractContext.ExecuteStrategy(num1, num2);
Console.Write("SubtractContext ExecuteStrategy Result:" + subtract + "\n\n");
Console.ReadKey();
}
}
5. 执行程序,输出结果
do OperationAdd [做加法运算]: 10 + 20 = 30
AddContext ExecuteStrategy Result is:30
do OperationMultiply [做乘法运算]:10 × 20 = 200
MultiplyContext ExecuteStrategy Result is:200
do OperationSubtract [做减法运算]:10 - 20 = -10
SubtractContext ExecuteStrategy Result:-10