策略模式

Android知识总结

一、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 方法)也是有运用到策略模式。

推荐阅读更多精彩内容