定義
策略模式定義了一系列的算法,并將每一個(gè)算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變化。
UML
實(shí)現(xiàn)
Strategy.java,策略類,定義算法的公共接口。
public abstract class Strategy {
// 算法方法
public abstract void algorithmInterface();
}
ConcreteStrategyA.java,算法A,封裝了具體算法,繼承Strategy。
public class ConcreteStrategyA extends Strategy {
@Override
public void algorithmInterface() {
System.out.println("算法A實(shí)現(xiàn)");
}
}
ConcreteStrategyB.java,算法B。
public class ConcreteStrategyB extends Strategy {
@Override
public void algorithmInterface() {
System.out.println("算法B實(shí)現(xiàn)");
}
}
ConcreteStrategyC.java,算法C。
public class ConcreteStrategyC extends Strategy {
@Override
public void algorithmInterface() {
System.out.println("算法C實(shí)現(xiàn)");
}
}
Context.java,上下文環(huán)境,維護(hù)Strategy引用。
public class Context {
private Strategystrategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void contextInterface() {
strategy.algorithmInterface();
}
}
StrategyTest.java,客戶端代碼。
public class StrategyTest {
public static void main(String[] args) {
Context context;
context = new Context(new ConcreteStrategyA());
context.contextInterface();
context = new Context(new ConcreteStrategyB());
context.contextInterface();
context = new Context(new ConcreteStrategyC());
context.contextInterface();
}
}
優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
1、 提供了一種替代繼承的方法,而且既保持了繼承的優(yōu)點(diǎn)(代碼重用),還比繼承更靈活(算法獨(dú)立,可以任意擴(kuò)展);
2、 避免程序中使用多重條件轉(zhuǎn)移語句,使系統(tǒng)更靈活,并易于擴(kuò)展;
3、 遵守大部分GRASP原則和常用設(shè)計(jì)原則,高內(nèi)聚、低偶合;
4、 易于進(jìn)行單元測試,各個(gè)算法區(qū)分開,可以針對每個(gè)算法進(jìn)行單元測試;
5、 ……
缺點(diǎn)
1、 因?yàn)槊總€(gè)具體策略類都會(huì)產(chǎn)生一個(gè)新類,所以會(huì)增加系統(tǒng)需要維護(hù)的類的數(shù)量;
2、 選擇何種算法需要客戶端來創(chuàng)建對象,增加了耦合,這里可以通過與工廠模式結(jié)合解決該問題;
3、 程序復(fù)雜化。
實(shí)例
需求
商場收銀系統(tǒng),實(shí)現(xiàn)對不同情況(正常收費(fèi)、折扣收費(fèi)、返利收費(fèi)等)的收費(fèi)。
實(shí)現(xiàn)
CashSuper.java,現(xiàn)金收費(fèi)父類。
/* 現(xiàn)金收費(fèi)父類 */
public abstract class CashSuper {
/* 收取現(xiàn)金方法,參數(shù)為商品原價(jià),返回值為當(dāng)前價(jià) */
public abstract double acceptCash(double money);
}
CashNormal.java,正常收費(fèi)。
/* 正常收費(fèi) */
public class CashNormal extends CashSuper {
@Override
public double acceptCash(double money) {
return money;
}
}
CashRebate.java,打折收費(fèi)。
/* 打折收費(fèi) */
public class CashRebate extends CashSuper {
/* 折扣率 */
private double moneyRebate;
public CashRebate(double moneyRebate) {
this.moneyRebate = moneyRebate;
}
@Override
public double acceptCash(double money) {
return money *moneyRebate;
}
}
CashReturn.java,返利收費(fèi)。
/* 返利收費(fèi) */
public class CashReturn extends CashSuper {
/* 返利滿足條件 */
private double moneyCondition;
/* 滿足條件后返回值 */
private double moneyReturn;
public CashReturn(double moneyCondition,double moneyReturn) {
this.moneyCondition = moneyCondition;
this.moneyReturn = moneyReturn;
}
@Override
public double acceptCash(double money) {
double result = 0;
result = money - Math.floor(money / moneyCondition) * moneyReturn;
return result;
}
}
CashContext.java,維護(hù)CashSuper對象。
public class CashContext {
private CashSupercs;
public CashContext(CashSuper cs) {
this.cs = cs;
}
public double getResult(double money) {
return cs.acceptCash(money);
}
}
CashTest.java,客戶端。
public class CashTest {
public static void main(String[] args) {
double money = 500;
CashContext context;
context = new CashContext(new CashNormal());
double normal = context.getResult(money);
System.out.println("正常收費(fèi):" + normal);
context = new CashContext(new CashRebate(0.8));
double rebate = context.getResult(money);
System.out.println("八折收費(fèi):" + rebate);
context = new CashContext(new CashReturn(200, 100));
double retur = context.getResult(money);
System.out.println("滿200返100:" + retur);
}
}
總結(jié)
策略模式和簡單工廠模式的區(qū)別
相同點(diǎn)
1、 都是用到了封裝、繼承、多態(tài);
2、 都抽出一個(gè)接口或者抽象類,針對不同的情況,有不同的實(shí)現(xiàn)類。
不同點(diǎn)
1、 使用方式不同,工廠是靜態(tài)的,策略的上下文是需要?jiǎng)?chuàng)建對象的;
2、 工廠產(chǎn)生的是對象,不同情況下產(chǎn)生不同的對象;
3、 策略產(chǎn)生的是策略,或者說是算法,不同情況下使用不同的算法。
結(jié)論
無論何種設(shè)計(jì)模式,都是基于面相對象的三大特性,即封裝、繼承、多態(tài)。