策略模式实现与研究 - bei1999/work GitHub Wiki

定义

个人觉得策略模式可以用这个公式:不同的XXX 拥有不同的XXX供用户选择。

场景模拟

最近在做自定义时钟,遇到一个需求,时钟的样式可以定义几种,比如指针类型的,比如自定义的样式的,或者是纯数字的形式.

实现

  • 不用任何模式实现
/**
 * Created by lzb on 2017/12/6.
 */

public class WatchViewImpl02 extends View {
    private int clockType;
    enum Strategy{
        DEFAULT,DESIGN,NROMAL
    }

    private Strategy strategy;

    public WatchViewImpl02(Context context) {
        super(context);
    }

    public WatchViewImpl02(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public WatchViewImpl02(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    public void setIClockStrategy(Strategy Strategy) {
        this.strategy = Strategy;
    }


    /**
     * 开始绘制钟表
     * @param canvas
     */
    public void paint(Canvas canvas) {
        if(strategy==Strategy.DEFAULT){
            //
        }else if(strategy==Strategy.DESIGN){
            //
        }else if(strategy==Strategy.NROMAL){
            //
        }

    }


}

  • 使用策略模式的实现 定义时钟接口
/**
 * 定义时钟接口
 */
public interface IClock {
    void paint(Canvas canvas);
}

/**
 * 时钟接口实现类
 */
public class DefaultClockImpl implements IClock {
    @Override
    public void paint(Canvas canvas) {

    }
}

/**
 * 设计的时钟样式类
 */
public class DesignClockImpl implements IClock {
    @Override
    public void paint(Canvas canvas) {

    }
}

/**
 * 普通的时钟样式类(数字形式)
 */
public class NormalClockImpl implements IClock {
    @Override
    public void paint(Canvas canvas) {

    }
}

/**
 * 手表的时钟样式类(指针表示)
 */
public class WatchViewImpl extends View {
    private IClock iClock;

    public WatchViewImpl(Context context) {
        super(context);
    }

    public WatchViewImpl(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public WatchViewImpl(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setIClock(IClock iClock) {
        this.iClock = iClock;
    }


    /**
     * 开始绘制钟表
     * @param canvas
     */
    public void paint(Canvas canvas) {
        iClock.paint(canvas);
    }


}
/**
 * 客户端测试
 * 
 * @author lzb
 */
public class WatchActivity extends Activity {
    private WatchViewImpl watchView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_watch);

        watchView = (WatchViewImpl) findViewById(R.id.watchview);

        IClock defaultClock = new DefaultClockImpl();
        IClock designClock = new DesignClockImpl();
        IClock normalClock  = new NormalClockImpl();

        watchView.setIClock(defaultClock);

    }
}

小结

从上面可以看出,如果我想定义这么多种样式用抽象类和接口肯定要copy一些重复的代码修改,多加if ..else 并且代码全部塞进了一个类中,有点混乱,这个时候用策略模式很好的解决了。

android 中的应用

安卓系统中策略模式也是应用的相当广泛的.最典型的就是属性动画中的应用,比如Interpolator类

//定义了一个差值器接口
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);
}

public interface Interpolator extends TimeInterpolator {
    // A new interface, TimeInterpolator, was introduced for the new android.animation
    // package. This older Interpolator interface extends TimeInterpolator so that users of
    // the new Animator-based animations can use either the old Interpolator implementations or
    // new classes that implement TimeInterpolator directly.
}


//抽象类实现了这个接口
/**
 * 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;
    }
}

//最后的不同样式实现
/**
 * An interpolator where the rate of change starts and ends slowly but
 * accelerates through the middle.
 */
@HasNativeInterpolator
public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    public AccelerateDecelerateInterpolator() {
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
    }
}

//另外一种样式的实现
/**
 * Repeats the animation for a specified number of cycles. The
 * rate of change follows a sinusoidal pattern.
 *
 */
@HasNativeInterpolator
public class CycleInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
    public CycleInterpolator(float cycles) {
        mCycles = cycles;
    }

    public CycleInterpolator(Context context, AttributeSet attrs) {
        this(context.getResources(), context.getTheme(), attrs);
    }

    /** @hide */
    public CycleInterpolator(Resources resources, Theme theme, AttributeSet attrs) {
        TypedArray a;
        if (theme != null) {
            a = theme.obtainStyledAttributes(attrs, R.styleable.CycleInterpolator, 0, 0);
        } else {
            a = resources.obtainAttributes(attrs, R.styleable.CycleInterpolator);
        }

        mCycles = a.getFloat(R.styleable.CycleInterpolator_cycles, 1.0f);
        setChangingConfiguration(a.getChangingConfigurations());
        a.recycle();
    }

    public float getInterpolation(float input) {
        return (float)(Math.sin(2 * mCycles * Math.PI * input));
    }

    private float mCycles;

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createCycleInterpolator(mCycles);
    }
}

总结

android 系统源码中策略模式随处可见,除了上面的属性动画差值器外,listview 的adapter,viewpager的提供几个Indicator接口的实现类,都是类似的的原理。