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

一、定义

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

二、角色

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.0
11-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. 对客户隐藏具体策略的算法实现细节,彼此完全独立。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值