买了大神关爱民与何红辉所著书籍《设计模式解析与实战》,观后有所感、有所悟。
对于同一个问题有多种处理方式,独立出各自的处理的方式,根据领导的决策选择对应的方式,这就是本篇要说的是策略模式。在开发中有一个抽象类,并拥有多个继承它子类,而有需要用到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里面有个属性动画详解课程,该网站视频全免费,高质量,大神开课,逗比也在这里学习了很多知识。