策略模式详解
设计模式总则第一条:对修改关闭,对扩展开放
抄了些东西:https://blog.csdn.net/tugangkai/article/details/88074288
策略模式的优点:
1.策略模式的功能就是通过抽象、封装来定义一系列的算法,使得这些算法可以相互替换,所以为这些算法定义一个公共的接口,以约束这些算法的功能实现。如果这些算法具有公共的功能,可以将接口变为抽象类,将公共功能放到抽象父类里面。
2.策略模式的一系列算法是可以相互替换的、是平等的,写在一起就是if-else组织结构,如果算法实现里又有条件语句,就构成了多重条件语句,可以用策略模式,避免这样的多重条件语句。
3.扩展性更好:在策略模式中扩展策略实现非常的容易,只要新增一个策略实现类,然后在使用策略实现的地方,使用这个新的策略实现就好了。
策略模式的缺点:
1.客户端必须了解所有的策略,清楚它们的不同:
如果由客户端来决定使用何种算法,那客户端必须知道所有的策略,清楚各个策略的功能和不同,这样才能做出正确的选择,但是这暴露了策略的具体实现。
2.增加了对象的数量:
由于策略模式将每个具体的算法都单独封装为一个策略类,如果可选的策略有很多的话,那对象的数量也会很多。
3.只适合偏平的算法结构:
由于策略模式的各个策略实现是平等的关系(可相互替换),实际上就构成了一个扁平的算法结构。即一个策略接口下面有多个平等的策略实现(多个策略实现是兄弟关系),并且运行时只能有一个算法被使用。这就限制了算法的使用层级,且不能被嵌套。
策略模式的本质:
分离算法,选择实现。
如果你仔细思考策略模式的结构和功能的话,就会发现:如果没有上下文,策略模式就回到了最基本的接口和实现了,只要是面向接口编程,就能够享受到面向接口编程带来的好处,通过一个统一的策略接口来封装和分离各个具体的策略实现,无需关系具体的策略实现。
貌似没有上下文什么事,但是如果没有上下文的话,客户端就必须直接和具体的策略实现进行交互了,尤其是需要提供一些公共功能或者是存储一些状态的时候,会大大增加客户端使用的难度;引入上下文之后,这部分工作可以由上下文来完成,客户端只需要和上下文进行交互就可以了。这样可以让策略模式更具有整体性,客户端也更加的简单。
策略模式体现了开闭原则:策略模式把一系列的可变算法进行封装,从而定义了良好的程序结构,在出现新的算法的时候,可以很容易的将新的算法实现加入到已有的系统中,而已有的实现不需要修改。
策略模式体现了里氏替换原则:策略模式是一个扁平的结构,各个策略实现都是兄弟关系,实现了同一个接口或者继承了同一个抽象类。这样只要使用策略的客户端保持面向抽象编程,就可以动态的切换不同的策略实现以进行替换。
下图为 随身听播放 – 歌手曲库的模型
歌手类可以任意扩展,比如加入张学友,加入张韶涵
对歌手-- sing() --唱歌这件事进行了封闭,不准修改
下面是代码实现:
1.运行
public class RunMainThread {
public static void main(String[] args) {
MyContext gemContext = new MyContext(new GEM());
gemContext.start();
}
}
2.上下文
/**
* 策略模式的上下文
* 赋值 -- 启动
*/
public class MyContext {
private Singer singer;
public MyContext(Singer singer) {
this.singer = singer;
}
public void start(){
singer.sing();
}
}
3.固定不变的规则 ---- 接口
/**
* 对扩展开放
*/
public interface Singer {
void sing();
}
4.可以增加,删除的具体类
/**
* 邓紫棋
*/
public class GEM implements Singer{
@Override
public void sing() {
System.out.println("喜欢你");
System.out.println("光年之外");
System.out.println("泡沫");
}
}
/**
* 周杰伦 对修改关闭
*/
public class JZhou implements Singer{
@Override
public void sing() {
System.out.println("七里香");
System.out.println("稻香");
System.out.println("兰亭序");
}
}
/**
* 刘德华
*/
public class LiuDeHua implements Singer {
@Override
public void sing() {
System.out.println("爱你一万年");
System.out.println("坏小孩");
System.out.println("开心马骝");
}
}
Android中用到的例子:
ListView 的 ListAdapter 是接口,
ArrayAdapter是子类,
ListView是上下文
- 如 setAdapter 里的 listAdapter.unregisterDataSetObserver(mDataSetObserver);