主目錄見:Android高級進(jìn)階知識(這是總目錄索引)
?策略模式應(yīng)該說應(yīng)用也是非常廣泛,而且很容易使用挟裂。有的人可能用到了但是沒有意識到莫湘,那么我們今天會(huì)讓大家意識到而且能在特定的場景中使用到他哄尔。我們這里先來看看他的定義:
策略模式定義了一些列的算法振愿,并將每一個(gè)算法封裝起來,而且使它們還可以相互替換红选。策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變換澜公。
這里的算法意思不是傳統(tǒng)的算法,其實(shí)就是一個(gè)action喇肋,就是一個(gè)獨(dú)立的執(zhí)行邏輯坟乾。策略模式可以獨(dú)立出來這些邏輯,然后在特定場景選擇特定的執(zhí)行邏輯蝶防。接著我們來看看他的UML類圖:
角色介紹:
- IStrategy:策略接口甚侣,定義了各個(gè)策略的公共接口
- ConcreteStrategy:具體的策略類,里面實(shí)現(xiàn)了策略接口中的策略方法慧脱。
- Context:用來操作各個(gè)策略的渺绒,利用具體的策略類進(jìn)行各種策略執(zhí)行。
一.目標(biāo)
我們今天的目標(biāo)跟之前講的設(shè)計(jì)模式也是一樣菱鸥,我們在明白別人使用的場景的時(shí)候自己遇到的時(shí)候也能利用起來宗兼。所以今天目標(biāo)也同樣是:
1.學(xué)會(huì)策略模式在什么場景下使用;
2.能在自己編寫框架的時(shí)候用上這個(gè)設(shè)計(jì)模式氮采。
二.模式解析
首先也是我們這里先假設(shè)一個(gè)場景:我們大學(xué)編程的時(shí)候殷绍,遇到一個(gè)編程題目解不出來,那么這時(shí)候有幾種情況可以解決鹊漠。一個(gè)是查看答案主到,一個(gè)是求教同學(xué),一個(gè)是請教老師躯概。那我們平常寫代碼可能是這樣:
public class StrategyPatternMain {
enum Strategy{
CHECK_ANSWER,SEARCH_HELP,CONSULT_TEACHER
}
private Strategy strategy;
public StrategyPatternMain(Strategy strategy){
super();
this.strategy = strategy;
}
public void doAction(){
switch (strategy) {
case CHECK_ANSWER:
System.out.println("查看答案");
break;
case SEARCH_HELP:
System.out.println("請教同學(xué)");
break;
case CONSULT_TEACHER:
System.out.println("請教老師");
break;
default:
break;
}
}
public static void main(String[] args) {
StrategyPatternMain homeWorkStrategy = new StrategyPatternMain(Strategy.SEARCH_HELP);
homeWorkStrategy.doAction();
StrategyPatternMain homeWorkStrategy2 = new StrategyPatternMain(Strategy.CHECK_ANSWER);
homeWorkStrategy2.doAction();
StrategyPatternMain homeWorkStrategy3 = new StrategyPatternMain(Strategy.CONSULT_TEACHER);
homeWorkStrategy3.doAction();
}
}
可以看到登钥,完美有沒有,你來一個(gè)新的方式我這邊可以再增加一個(gè)case娶靡,靈活有沒有牧牢。然后最后你想到方法越來越多,這個(gè)類就被修改了無數(shù)遍姿锭,代碼就是一坨一坨的塔鳍,這時(shí)候你想,不行呀呻此,我應(yīng)該讓他可以組裝呀轮纫,而且不影響原有的代碼。那么策略模式就蹦出來了焚鲜。
1.策略模式
我們這里解決這個(gè)擴(kuò)展困難問題掌唾,我們這里引入策略模式放前,首先我們先來看看策略接口:
public interface IStrategy {
void doAction();
}
這個(gè)策略接口類很簡單,就是一個(gè)方法郑兴,然后我們來看看幾個(gè)具體策略類:
public class CheckAnswer implements IStrategy {
@Override
public void doAction() {
System.out.println("查看答案");
}
}
public class SearchHelp implements IStrategy {
@Override
public void doAction() {
System.out.println("請教同學(xué)");
}
}
public class ConsultTeacher implements IStrategy {
@Override
public void doAction() {
System.out.println("請教老師");
}
}
我們看到幾個(gè)策略類也是非常簡單的犀斋,就是簡單地執(zhí)行各自的打印動(dòng)作贝乎。然后我們看下Context類:
public class Context {
private IStrategy strategy;
public void setStrategy(IStrategy strategy){
this.strategy = strategy;
}
public void doAction(){
strategy.doAction();
}
}
我們看到這里面持有了一個(gè)策略類的引用情连,然后在方法里面調(diào)用相應(yīng)的action。我們看下這個(gè)怎么使用:
IStrategy checkAnswer = new CheckAnswer();
IStrategy searchHelp = new SearchHelp();
IStrategy consultTeacher = new ConsultTeacher();
Context context = new Context();
context.setStrategy(checkAnswer);
context.doAction();
context.setStrategy(searchHelp);
context.doAction();
context.setStrategy(consultTeacher);
context.doAction();
我們看到這邊如果增加了尋找解決問題的方法览效,我們只要增加一個(gè)具體策略類却舀,然后在使用的時(shí)候,設(shè)置進(jìn)去就可以了锤灿,這樣的話面對擴(kuò)展就非常地方便挽拔。這也是我們?yōu)樯兑褂眠@個(gè)模式的原因。
2.屬性動(dòng)畫中策略模式的使用
屬性動(dòng)畫中的插值器(Interpolator)和估值器(Evaluator)的使用就是用的策略模式但校,我們先來看下插值器螃诅。我們先來看下之前寫過一篇[屬性動(dòng)畫基礎(chǔ)用法]中有個(gè)屬性用法是這樣的:
Point endPoint = new Point(getWidth() - RADIUS,getHeight() - RADIUS);
ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(),currentPoint,endPoint);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
currentPoint = (Point) valueAnimator.getAnimatedValue();
invalidate();
}
});
//這里設(shè)置了插值器
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
valueAnimator.setDuration(2000);
valueAnimator.start();
我們看到這里設(shè)置了具體的插值器,那么我們來分析下這里面的策略模式的各個(gè) 角色状囱,首先就是Context角色术裸,這個(gè)很明顯就是ValueAnimator,我們看下他的setInterpolator方法:
@Override
public void setInterpolator(TimeInterpolator value) {
if (value != null) {
mInterpolator = value;
} else {
mInterpolator = new LinearInterpolator();
}
}
可以看到這個(gè)里面設(shè)置了具體插值器的引用亭枷。然后我們看看具體插值器也就是具體策略類的實(shí)現(xiàn):
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public LinearInterpolator() {
}
public LinearInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return input;
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
}
}
我們看到這個(gè)具體插值器繼承了BaseInterpolator 并且實(shí)現(xiàn)了NativeInterpolatorFactory袭艺。這里的BaseInterpolator 實(shí)際又實(shí)現(xiàn)了Interpolator,然后Interpolator又實(shí)現(xiàn)了TimeInterpolator:
public interface TimeInterpolator {
float getInterpolation(float input);
}
所以TimeInterpolator 我們這里可以當(dāng)做抽象插值器類也就是抽象策略類叨粘』啵看到這里我們已經(jīng)把每個(gè)策略模式的角色都分出來了。其實(shí)是非常簡單的升敲,但是達(dá)到的效果確實(shí)符合程序優(yōu)秀設(shè)計(jì)的思想答倡。至于估值器其實(shí)也是類似的,這里就不舉那么多例子了驴党,大家看懂就可以瘪撇。其實(shí)在Glide里面大家設(shè)置緩存策略的時(shí)候也會(huì)用到策略設(shè)計(jì)模式,大家有興趣可以自己也看看鼻弧。
總結(jié):策略模式使用簡單设江,場景也非常多,記住遇到if-else攘轩,switch特別多的場景叉存,同時(shí)程序后面可能會(huì)變化,條件會(huì)增加度帮。這時(shí)候往往就是策略模式派上用場的時(shí)候歼捏,所以我們平常用設(shè)計(jì)模式的時(shí)候要多想多用稿存。