現實中很多裝置要根據某些數值來計算出其他值,如已知園的半徑求其面積、已知三角形三邊求其周長等等還有一些工藝裝置也會用到此類方法,歸根到底就是應用一個公式來算出相應的屬性值。現在以三角形為例來學習此類問題的解決方案。
基本需求:根據三邊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種裝置,每種裝置都存在這樣的多種演算法情況,可能某些裝置存在三四種演算法,那類的數量將是很大的。沒有完美的設計只有適合的設計。
PS:附上結構圖