一、UML类图
策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。
角色说明:
- Stragety(抽象策略类):抽象类或接口,提供具体策略类需要实现的接口。
- ConcreteStragetyA、ConcreteStragetyB(具体策略类):具体的策略实现,封装了相关的算法实现。
- Context(环境类):用来操作策略的上下文环境。
二、实现
1. 创建抽象策略类
public interface ChaseStragety {//追求策略
void chase();//抽象追求方法
}
2. 创建具体策略类
public class ShoppingStrategy implements ChaseStragety {
@Override
public void chase() {
System.out.println("一起逛街咯~");
}
}
public class MoviesStrategy implements ChaseStragety {
@Override
public void chase() {
System.out.println("一起看电影咯~");
}
}
public class EattingStrategy implements ChaseStragety {
@Override
public void chase() {
System.out.println("一起吃饭咯~");
}
}
3. 创建环境类
public class Context {
private ChaseStragety chaseStragety;//定义抽象策略类
public Context(ChaseStragety chaseStragety) {//构造方法传递具体策略对象过来
this.chaseStragety = chaseStragety;
}
public void chase(){//执行具体策略对象的策略
chaseStragety.chase();
}
}
4. 测试方法
public void test(){
Context context;
System.out.println("遇到爱逛街的妹子:");
context=new Context(new ShoppingStrategy());
context.chase();
System.out.println("遇到爱看电影的妹子:");
context=new Context(new MoviesStrategy());
context.chase();
System.out.println("遇到吃货妹子:");
context=new Context(new EattingStrategy());
context.chase();
}
输出结果:
遇到爱逛街的妹子:
一起逛街咯~
遇到爱看电影的妹子:
一起看电影咯~
遇到吃货妹子:
一起吃饭咯~
三、优点
- 策略类可以互相替换
由于策略类都实现同一个接口,因此他们能够互相替换。 - 耦合度低,方便扩展
增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合开闭原则。 - 避免使用多重条件选择语句(if-else或者switch)。
四、 缺点
- 策略的增多会导致子类的也会变多
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
五、Android中的源码分析
我们用的ListView时都需要设置一个Adapter,而这个Adapter根据我们实际的需求可以用ArrayAdapter、SimpleAdapter等等,这里就运用到策略模式。
1. ListView的简单用法
listView = (ListView)findViewById(R.id.list_view);
//使用ArrayAdapter
listView.setAdapter(new ArrayAdapter<String>(this,R.id.item,new String[] {"one","two"}));
//使用BaseAdapter
listView.setAdapter(new BaseAdapter() {
@Override
public int getCount() {
return 0;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
});
2. 相关源码分析
public class ListView extends AbsListView {//相当于环境类
@Override
public void setAdapter(ListAdapter adapter) {//设置策略,即adapter
//其他代码略
}
}
public interface ListAdapter extends Adapter {//抽象策略接口
}
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {//具体策略类BaseAdapter,实现ListAdapter接口
}
public class ArrayAdapter<T> extends BaseAdapter implements Filterable, ThemedSpinnerAdapter {//具体策略类ArrayAdapter,继承BaseAdapter,即实现ListAdapter接口
}
3. 总结
- 通过设置不同的Adapter(即不同的策略),我们就可以写出符合我们需求的ListView布局。
- 另外,动画中的插值器(ValueAnimator 的 setInterpolator 方法)也是有运用到策略模式。
网友评论