策略模式定义了一些列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变换。

假设我们要出去旅游,而去旅游出行的方式有很多,有步行,有坐火车,有坐飞机等等。而如果不使用任何模式,我们的代码可能就是这样子的。

public class TravelStrategy {
enum Strategy{
WALK,PLANE,SUBWAY
}
private Strategy strategy;
public TravelStrategy(Strategy strategy){
this.strategy=strategy;
} public void travel(){
if(strategy==Strategy.WALK){
print("walk");
}else if(strategy==Strategy.PLANE){
print("plane");
}else if(strategy==Strategy.SUBWAY){
print("subway");
}
} public void print(String str){
System.out.println("出行旅游的方式为:"+str);
} public static void main(String[] args) {
TravelStrategy walk=new TravelStrategy(Strategy.WALK);
walk.travel(); TravelStrategy plane=new TravelStrategy(Strategy.PLANE);
plane.travel(); TravelStrategy subway=new TravelStrategy(Strategy.SUBWAY);
subway.travel();
}
}

这样做有一个致命的缺点,一旦出行的方式要增加,我们就不得不增加新的else if语句,而这违反了面向对象的原则之一,对修改封闭。而这时候,策略模式则可以完美的解决这一切。

首先,需要定义一个策略接口。

public interface Strategy {
void travel();
}

然后根据不同的出行方式实行对应的接口

public class WalkStrategy implements Strategy{

	@Override
public void travel() {
System.out.println("walk");
} }
public class PlaneStrategy implements Strategy{

	@Override
public void travel() {
System.out.println("plane");
} }
public class SubwayStrategy implements Strategy{

	@Override
public void travel() {
System.out.println("subway");
} }

此外还需要一个包装策略的类,并调用策略接口中的方法

public class TravelContext {
Strategy strategy; public Strategy getStrategy() {
return strategy;
} public void setStrategy(Strategy strategy) {
this.strategy = strategy;
} public void travel() {
if (strategy != null) {
strategy.travel();
}
}
}

测试一下代码

public class Main {
public static void main(String[] args) {
TravelContext travelContext=new TravelContext();
travelContext.setStrategy(new PlaneStrategy());
travelContext.travel();
travelContext.setStrategy(new WalkStrategy());
travelContext.travel();
travelContext.setStrategy(new SubwayStrategy());
travelContext.travel();
}
}

输出结果如下

plane
walk
subway

可以看到,应用了策略模式后,如果我们想增加新的出行方式,完全不必要修改现有的类,我们只需要实现策略接口即可,这就是面向对象中的对扩展开放准则。假设现在我们增加了一种自行车出行的方式。只需新增一个类即可。

public class BikeStrategy implements Strategy{

	@Override
public void travel() {
System.out.println("bike");
} }

之后设置策略即可

public class Main {
public static void main(String[] args) {
TravelContext travelContext=new TravelContext();
travelContext.setStrategy(new BikeStrategy());
travelContext.travel();
}
}

而在Android的系统源码中,策略模式也是应用的相当广泛的.最典型的就是属性动画中的应用.

我们知道,在属性动画中,有一个东西叫做插值器,它的作用就是根据时间流逝的百分比来来计算出当前属性值改变的百分比.

我们使用属性动画的时候,可以通过set方法对插值器进行设置.可以看到内部维持了一个时间插值器的引用,并设置了getter和setter方法,默认情况下是先加速后减速的插值器,set方法如果传入的是null,则是线性插值器。而时间插值器TimeInterpolator是个接口,有一个接口继承了该接口,就是Interpolator这个接口,其作用是为了保持兼容

private static final TimeInterpolator sDefaultInterpolator =
new AccelerateDecelerateInterpolator();
private TimeInterpolator mInterpolator = sDefaultInterpolator;
@Override
public void setInterpolator(TimeInterpolator value) {
if (value != null) {
mInterpolator = value;
} else {
mInterpolator = new LinearInterpolator();
}
} @Override
public TimeInterpolator getInterpolator() {
return mInterpolator;
}
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.
}

此外还有一个BaseInterpolator插值器实现了Interpolator接口,并且是一个抽象类

abstract public class BaseInterpolator implements Interpolator {
private int mChangingConfiguration;
/**
* @hide
*/
public int getChangingConfiguration() {
return mChangingConfiguration;
} /**
* @hide
*/
void setChangingConfiguration(int changingConfiguration) {
mChangingConfiguration = changingConfiguration;
}
}

平时我们使用的时候,通过设置不同的插值器,实现不同的动画速率变换效果,比如线性变换,回弹,自由落体等等。这些都是插值器接口的具体实现,也就是具体的插值器策略。我们略微来看几个策略。

public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public LinearInterpolator() {
} public LinearInterpolator(Context context, AttributeSet attrs) {
} public float getInterpolation(float input) {
return input;
} /** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
}
}
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();
}
}

内部使用的时候直接调用getInterpolation方法就可以返回对应的值了,也就是属性值改变的百分比。

Android开发中常见的设计模式(四)——策略模式的更多相关文章

  1. Android开发中常见的设计模式 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. Android开发中无处不在的设计模式——动态代理模式

    继续更新设计模式系列.写这个模式的主要原因是近期看到了动态代理的代码. 先来回想一下前5个模式: - Android开发中无处不在的设计模式--单例模式 - Android开发中无处不在的设计模式-- ...

  3. Android开发中常见的设计模式

    对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次.而在android开发中,必要的了解一些设计模式又是非常有必要的.对于想系统的学习设计模式的 ...

  4. Android开发中常见的设计模式(二)——Builder模式

    了解了单例模式,接下来介绍另一个常见的模式--Builder模式. 那么什么是Builder模式呢.通过搜索,会发现大部分网上的定义都是 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建 ...

  5. Android开发中常见的设计模式(一)——单例模式

    首先了解一些单例模式的概念. 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 这样做有以下几个优点 对于那些比较耗内存的类,只实例化一次可以大大提高性能,尤其是在移动开发中. 保持 ...

  6. Android开发中常见的设计模式(三)——观察者模式

    先看下这个模式的定义. 定义对象间的一种一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都能得到通知并被自动更新 先来讲几个情景. 情景1:有一种短信服务,比如天气预报服务,一旦你订阅 ...

  7. Android开发中常用的设计模式

    首先需要说明的是,这篇博文灵感来自于 http://www.cnblogs.com/qianxudetianxia/archive/2011/07/29/2121547.html ,在这里,博主已经很 ...

  8. Android 开发中常见的注意点

    这里总结了Android开发中常用的注意点.只有总结,没有展开举例讲解,展开的话,一个点都可以写一篇文章了..... 这类问题都一定不要犯. 重要的事情说三遍!!! 说三遍!!! 遍!!! 资源 不允 ...

  9. iOS 开发中常见的设计模式

    最近有小伙伴问到在iOS开发中的几种设计模式,这里摘录一下别人的总结(因为已经感觉总结得差不多了,适用的可以阅读一下) 首先是开发中的23中设计模式分为三大类:1.创建型 2.结构型 3.行为型 (i ...

随机推荐

  1. box-sizing的用法

        默认情况下设置盒子的width是指内容区域,所以在设置边框会使得盒子往外扩张,如果要让css设置的width就是盒子最终的宽度,那么就要设置box-sizing:border-box,     ...

  2. while +for+字符串

    # while 循环嵌套# user_from_db='egon'# pwd_from_db='123'# while True:# usr_inp=input('username>>&g ...

  3. 2019.4 sigfox EMC

    干扰源: ------- Leakage Sensor 有-30dB的谐波 1在NPN 基级加100pF 电容 从VCC到GND,一级级整改.

  4. 读取Excel表格中数据原型

    写下这篇博客来记录自己的工作,这部分功能是读取Excel表格中的数据,并通过c#中的datagridview控件将读取的数据显示出来.为了方便用户,我设计了一个read按钮,用户点击这个按钮,会弹出打 ...

  5. [转]Spark学习之路 (三)Spark之RDD

    Spark学习之路 (三)Spark之RDD   https://www.cnblogs.com/qingyunzong/p/8899715.html 目录 一.RDD的概述 1.1 什么是RDD? ...

  6. 构建gulp项目

    express是node.js中的构建工具,如果需要使用express构建,首先需要安装express. 构建一个项目: |-- app| |-- css| |-- js| | `-- class| ...

  7. vue2.0 父子组件通信 兄弟组件通信

    父组件是通过props属性给子组件通信的来看下代码: 父组件: <parent> <child :child-com="content"></chil ...

  8. alpha冲刺(7/10)

    前言 队名:旅法师 作业链接 队长博客 燃尽图 会议 会议照片 会议内容 陈晓彬(组长) 今日进展: 召开会议 撰写博客 项目初步整合前端代码 问题困扰: 大家可能因为某些问题会联系卡在某个点很久,需 ...

  9. selenium 网络请求

    selenium 网络请求 browser.find_element_by_id("id的name")browser.find_element("")brows ...

  10. POI导出Execl文件,使JAVA虚拟机OOM

    由于在项目中使用POI导出execl,导致JAVA虚拟机OOM,采用以下方式解决问题: 原先方式: g_wb = new XSSFWorkbook(sourceFile.getInputStream( ...