设计模式之----策略模式(ListAdapter和TimeInterpolator源码分析)

来源:互联网 发布:如何优化listing 编辑:程序博客网 时间:2024/05/16 08:06

一、定义

策略模式定义了一系列算法,并将每一个算法封装起来,而且使他们之间可以相互替换,策略模式让算法独立于使它的客户独立而变化。
策略模式的重点不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。

二、角色

2.1 环境(Context)角色

该角色持有一个Stragtegy的引用,可以执行Stragtegy的方法

2.2 抽象策略(Stragtegy)角色

这是一个抽象角色,通常由一个接口或者抽象类实现,此角色给出所有的具体策略角色共同的接口,部分不需要子类实现的部分可在该角色中实现。

2.3 具体策略(ConcreteStragtegy)角色

包装了相关的算法或者行为。

三、需求

假设现在要一个上商店个搞活动。 对所有的高级会员打20%的促销折扣;对中级会员打10%的促销折扣;对初级会员没有折扣。

得知算法:

  • 算法一:对初级会员没有折扣。
  • 算法二:对中级会员提供10%的促销折扣。
  • 算法三:对高级会员提供20%的促销折扣。

四、代码实现

4.1 抽象策略角色实现

/** * 抽象策略角色,定义接口 * * Created by rytong on 2017/11/2. */public interface Stragtegy {    /**     * 获取真实价格     *     * @param price     * @return     */    public double getPrice(double price);}

4.2 具体策略角色实现

/** * 普通策略角色:高级会员打8折 * * Created by rytong on 2017/11/2. */public class Stragtegy3 implements Stragtegy {    @Override    public double getPrice(double price) {        return price*0.8;    }}

4.3 上下文角色实现

/** * 上下文角色,持有Stragtegy角色 * * Created by rytong on 2017/11/2. */public class StragtegyContext {    //具体的策略角色    Stragtegy mStragtegy;    public StragtegyContext(Stragtegy mStragtegy) {        this.mStragtegy = mStragtegy;    }    /**     * 计算实际价格     * @param price     * @return     */    public double calcutatePrice(double price){        return mStragtegy.getPrice(price);    }}

4.4 客户端调用

//高级会员Stragtegy stragtegy3 = new Stragtegy3();StragtegyContext stragtegyContext = new StragtegyContext(stragtegy3);Log.e(TAG,"高级会员打折后的价格:"+stragtegyContext.calcutatePrice(1000));// 改为中级会员stragtegyContext = new StragtegyContext(new Stragtegy2());Log.e(TAG,"中级会员打折后的价格:"+stragtegyContext.calcutatePrice(1000));

执行结果:

11-02 15:57:12.958 1812-1812/? E/MainActivity: 高级会员打折后的价格:800.011-02 15:57:12.959 1812-1812/? E/MainActivity: 中级会员打折后的价格:900.0

五、安卓中的策略模式

5.1 ListView的Adapter

5.1.1 客户端调用

给每个listView设置adapter的时候需要继承BaseAdapter,并重写各方法来完成,这个地方可以替换为任何的ListAdapter接口的子类都可以。

ListView listView = new ListView(this);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;    }});

5.1.2 源码查看

  1. 从调用点查看:在AbsListView中声明一个ListAdapter,在调用setAdapter的时候赋值。ListAdapter就是抽象策略角色,我们实现的Adapter就是具体策略角色。ListView就是上下文角色。

    public void setAdapter(ListAdapter adapter) {if (mAdapter != null && mDataSetObserver != null) {    mAdapter.unregisterDataSetObserver(mDataSetObserver);}resetList();mRecycler.clear();if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {    mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);} else {    mAdapter = adapter;}...}
  2. mAdapter的使用:有很多地方都有,找一个简单的

    public boolean removeHeaderView(View v) {if (mHeaderViewInfos.size() > 0) {    boolean result = false;    if (mAdapter != null && ((HeaderViewListAdapter) mAdapter).removeHeader(v)) {        if (mDataSetObserver != null) {            mDataSetObserver.onChanged();        }        result = true;    }    removeFixedViewInfo(v, mHeaderViewInfos);    return result;}return false;}

5.2 插值器

5.2.1 客户端调用

在客户端调用的时候指定插值器的类型,来指定动画的类型。这里ObjectAnimator类就是上下文角色,LinearInterpolator是具体策略角色,TimeInterpolator是抽象策略角色。

TextView textView = new TextView(this);ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(textView, View.SCALE_X, 0f, 1f);objectAnimator.setDuration(2000);objectAnimator.setRepeatMode(ValueAnimator.RESTART);objectAnimator.setRepeatCount(-1);//插值器objectAnimator.setInterpolator(new LinearInterpolator());objectAnimator.start();

5.2.2 源码简单查看

public void setInterpolator(TimeInterpolator value) {    if (value != null) {        mInterpolator = value;    } else {        mInterpolator = new LinearInterpolator();    }}

六、总结

6.1 优点

  1. 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或者行为族。恰当的继承可以把公共的代码移到父类里面,从而避免代码重复。
  2. 使用策略模式可以避免使用多重if-else类语句。把每个分支封装为一种行为单独封装。

6.2 缺点

  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便选择恰当的算法使用。换言之,策略模式只适用于客户端知道算法或者行为的情况。
  2. 由于策略模式把每一个具体的策略封装成了类,所以类文件数量会比较可观。

6.3 特点

  1. 运行时策略唯一性:在运行时只能有一个生效。
  2. 平等性:在调用的地方可以使用任意一个具体的策略。他们之间是相互独立,没有依赖的。

6.3 使用场景

  1. 多个类只区别在表现行为不同,可以使用Stragtgy模式,在运行时动态选择具体要执行的行为
  2. 需要在不同的情况下使用不同的策略(算法、行为),或者策略还可能在未来用其他方式来实现(容易扩展)
  3. 对客户隐藏具体策略的算法实现细节,彼此完全独立。
原创粉丝点击