设计模式解析与实战之策略模式

买了大神关爱民与何红辉所著书籍《设计模式解析与实战》,观后有所感、有所悟。

对于同一个问题有多种处理方式,独立出各自的处理的方式,根据领导的决策选择对应的方式,这就是本篇要说的是策略模式。在开发中有一个抽象类,并拥有多个继承它子类,而有需要用到switch-case 、if-else来做选择时,这时候就可以考虑策略模式。

下面通过模拟饿了么APP的支付选择界面,来让我们来理解策略模式。需求如下:购买了商品,然后到支付界面去支付,如果选择腾讯支付,满足一定的条件立即减价格,更具梯度变化,如果选择百度钱包支付也同理,只是各自的价格区间立减不同。

支付实体对象 PayEntity.java


import java.io.Serializable;

public class PayEntity implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = -9112599394539789002L;

    /**支付名称*/
    private String payName;
    /**支付类型*/
    private int payType;
    /**支付价格*/
    private float price;
    public String getPayName() {
        return payName;
    }
    public void setPayName(String payName) {
        this.payName = payName;
    }
    public int getPayType() {
        return payType;
    }
    public void setPayType(int payType) {
        this.payType = payType;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
    public static long getSerialversionuid() {
        return serialVersionUID;
    }
    public PayEntity(String payName, int payType, float price) {
        super();
        this.payName = payName;
        this.payType = payType;
        this.price = price;
    }

}

支付策略接口PayStrategy .java

public interface PayStrategy {

    float caculate(float price);
}

腾讯支付策略TecentPayStrategy .java


public class TecentPayStrategy implements PayStrategy{

    @Override
    public float caculate(float price) {
        float result=0;
        if(price>100){
            result=price-10;
        }else if(price>50){
            result=price-5;
        }else if(price>20){
            result=price-2;
        }
        return result;
    }

}

百度钱包支付策略BaiduPayStrategy .java

public class BaiduPayStrategy implements PayStrategy {

    @Override
    public float caculate(float price) {
        float result=0;
        if(price>100){
            result=price-20;
        }else if(price>50){
            result=price-10;
        }else if(price>20){
            result=price-3;
        }
        return result;
    }

}

策略工厂方法类


public class StrategyFactory implements OnPayListener{

    private PayEntity mBasePay;

    public StrategyFactory() {
        this(null);
    }
    public StrategyFactory(PayEntity mBasePay) {
        setBasePay(mBasePay);
    }

    @Override
    public void setBasePay(PayEntity mBasePay) {
        this.mBasePay=mBasePay; 
    }

    @Override
    public PayEntity getBasePay() {
        return mBasePay;
    }

    public float caculate(){

        float result=0;

        if(getBasePay().getPayType()==0){
            result=new BaiduPayStrategy().caculate(getBasePay().getPrice());
        }else if(getBasePay().getPayType()==1){
            result=new TecentPayStrategy().caculate(getBasePay().getPrice());
        }

        return result;
    }

}

接口OnPayListener:


public interface OnPayListener{

    void setBasePay(PayEntity mBasePay);

    PayEntity getBasePay();
}

下面是测试代码和结果:

public class StrategyTest {

    public static void main(String[] args) {

        PayEntity mEntity=new PayEntity("百度钱包支付", 0, 123f);
        System.out.println("实付价格:"+new StrategyFactory(mEntity).caculate());
    }
}

//测试结果:实付价格:103.0

策略模式让代码结构清晰明了,耦合度相对较低,扩展方便,封装彻底数据也安全,但是不足之处就是策略类多,有强迫症的人对于这点看不惯可以忽略该模式,下面再来看看策略模式在源码中的实战。

动画中的时间差值器:TimeInterpolator:

public interface TimeInterpolator {

    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}

BaseInterpolator继承Interpolator接口继承TimeInterpolator:

/**
 * An abstract class which is extended by default interpolators.
 */
abstract public class BaseInterpolator implements Interpolator {
    private int mChangingConfiguration;
    /**
     * @hide
     */
    public int getChangingConfiguration() {
        return mChangingConfiguration;
    }

    /**
     * @hide
     */
    void setChangingConfiguration(int changingConfiguration) {
        mChangingConfiguration = changingConfiguration;
    }
}

DecelerateInterpolator和LinearInterpolator两个差之器的策略对比如下:


/**
 * An interpolator where the rate of change is constant
 */
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public float getInterpolation(float input) {
        return input;
    }
    //................此处略..................................
}


/**
 * An interpolator where the rate of change starts out quickly and
 * and then decelerates.
 *
 */
@HasNativeInterpolator
public class DecelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public float getInterpolation(float input) {
        float result;
        if (mFactor == 1.0f) {
            result = (float)(1.0f - (1.0f - input) * (1.0f - input));
        } else {
            result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
        }
        return result;
    }
      //................此处略..................................

}

根据以上对比可以发现,View在onDraw绘制时,调用drawAnimation绘制动画,通过getTransformation方法具体实现动画,在该方法中使用到策略模式,不同的差之器有不同的计算Interpolator的计算方法,该方法的具体实现代码如下:

 /**
     * Gets the transformation to apply at a specified point in time. Implementations of this
     * method should always replace the specified Transformation or document they are doing
     * otherwise.
     *
     * @param currentTime Where we are in the animation. This is wall clock time.
     * @param outTransformation A transformation object that is provided by the
     *        caller and will be filled in by the animation.
     * @return True if the animation is still running
     */
    public boolean getTransformation(long currentTime, Transformation outTransformation) {
        if (mStartTime == -1) {
            mStartTime = currentTime;
        }

        final long startOffset = getStartOffset();
        final long duration = mDuration;
        float normalizedTime;
        if (duration != 0) {
            normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
                    (float) duration;
        } else {
            // time is a step-change with a zero duration
            normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
        }

        final boolean expired = normalizedTime >= 1.0f;
        mMore = !expired;

        if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);

        if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
            if (!mStarted) {
                fireAnimationStart();
                mStarted = true;
                if (USE_CLOSEGUARD) {
                    guard.open("cancel or detach or getTransformation");
                }
            }

            if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);

            if (mCycleFlip) {
                normalizedTime = 1.0f - normalizedTime;
            }

            final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
            applyTransformation(interpolatedTime, outTransformation);
        }

        if (expired) {
            if (mRepeatCount == mRepeated) {
                if (!mEnded) {
                    mEnded = true;
                    guard.close();
                    fireAnimationEnd();
                }
            } else {
                if (mRepeatCount > 0) {
                    mRepeated++;
                }

                if (mRepeatMode == REVERSE) {
                    mCycleFlip = !mCycleFlip;
                }

                mStartTime = -1;
                mMore = true;

                fireAnimationRepeat();
            }
        }

        if (!mMore && mOneMoreTime) {
            mOneMoreTime = false;
            return true;
        }

        return mMore;
    }

对于属性动画这块的学习如果想深入了解更多,推荐http://www.imooc.com里面有个属性动画详解课程,该网站视频全免费,高质量,大神开课,逗比也在这里学习了很多知识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值