从△走进OO,走进策略模式
现实中很多设备要根据某些数值来计算出其他值,如已知园的半径求其面积、已知三角形三边求其周长等等还有一些工艺设备也会用到此类方法,归根到底就是应用一个公式来算出相应的属性值。现在以三角形为例来学习此类问题的解决方法。
基本需求:根据三边a、b、c求三角形周长。
基本抽象:一个三角形类Triangle,有一个求周长的方法GetCirByABC();
基本实现:
public class Triangle
{
public double GetCirByABC(double a, double b, double c)
{
return a + b + c;
}
}
基本不足:依照OO的抽象不应依赖细节,显然a、b、c以及返回值都定位到相应的属性了,违背了抽象不依赖细节原则,故应直接返回一个Triangle对象,他的好处之一就是需要什么值就通过属性来取相应的值,好处之二后面会提到。
改进后的实现:
public class Triangle
{
public double A { get; set; }
public double B { get; set; }
public double C { get; set; }
public double Cir { get; set; }
public Triangle GetModel(Triangle tg)
{
tg.Cir = tg.A + tg.B + tg.C;
return tg;
}
}
扩展需求:根据A和B边以及Cir周长求C边长度,看似直接增加一个方法即可解决。
public Triangle GetModel(Triangle tg)
{
tg.C = tg.Cir - tg.A - tg.B;
return tg;
}
可以观察到直接返回对象的好处二,不变的是抽象,只是算法发生了变化,由此策略模式应运而生。
策略模式(Strategy):他定义了一系列的算法,并将每一种算法封装起来,并且可以相互替换,新的算法诞生不会造成类结构的破坏,只是一种扩展而已。
策略抽象类定义:
abstract class Strategy
{
public abstract Triangle GetModel(Triangle tg);
}
2个具体策略类定义CirByABCStrategy和CByCirABStrategy:
//根据周长和AB边求C
class CByCirABStrategy:Strategy
{
public override Triangle GetModel(Triangle tg)
{
tg.C = tg.Cir - tg.A - tg.B;
return tg;
}
}
//根据ABC求周长
class CirByABCStrategy:Strategy
{
public override Triangle GetModel(Triangle tg)
{
tg.Cir = tg.A + tg.B + tg.C;
return tg;
}
}
上下文类Context(保存一个策略类的引用)定义:
class Context
{
private Strategy strategy;
public Context(Strategy strategy)
{
this.strategy = strategy;
}
public Triangle ContextInface(Triangle tg)
{
return strategy.GetModel(tg);
}
}
客户端求周长调用例子:
Triangle triangle = new Triangle();
triangle.A = 3;
triangle.B = 4;
triangle.C = 5;
Context context = new Context(new CirByABCStrategy());//这里决定调用具体的策略类,如果是根据AB和Cir来求则为new CByCirABStrategy();
Triangle tg = context.ContextInface(triangle);
Console.WriteLine("策略模式求周长:" + tg.Cir);
策略模式缺点:实施起来较复杂,如有N种设备,每种设备都存在这样的多种算法情况,可能某些设备存在三四种算法,那类的数量将是很大的。没有完美的设计只有适合的设计。