版权声明:本文为博主原创文章,未经博主容许不得转载java
PS:转载请注明出处
做者: TigerChain
地址: http://www.jianshu.com/p/135532803cdb
本文出自 TigerChain 简书 Android设计模式系列react
教程简介android
正文git
好比说我要出行旅游,那么出行方式有--飞机、自驾游、火车等,这几种方式就是策略。再好比:某大型商场搞活动--满 100 元送杯子,满 300 减 50 ,满 1000 元抽奖「一等将彩色电视机」,这种活动也是策略。在游戏中,咱们打一个普通的怪使用普通的招便可,打大 BOSS 就要是用大招,这也是一种策略 ...github
就是对各个算法的一个封装「不是实现算法,而是封装算法」,让客户端很是容易的调用,省掉了客户端 if else 恶心的判断,让客户端独立于各个策略算法
这里举一个简单的例子:好比咱们在 Android 中必定会使用到 http 网络请求,请求库太多了,大概有 AsyncHttpclient,OkhttpClient,Volley 等「具体的策略」,那么咱们彻底可使用一个策略模式,定义一个抽像策略,而后把各个请求策略封装,客户想使用哪一个就使用哪一个,很是灵活和方便设计模式
策略模式和简单工厂很类似,确有不一样,策略是一种行为模式,而简单工厂是建立型模式「建立对象」 后面再说安全
策略模式的定义服务器
策略是对算法的封装,是一种形为模式,将每个算法封装到具备共同接口的独立的类中,从而使得它们能够相互替换网络
策略的特色
策略模式的结构
角色 | 类别 | 说明 |
---|---|---|
Strategy | 抽象的策略 | 是一个接口或抽象类 |
ConcreteStrategy | 具体的策略类 | 实现了抽象的策略 |
Context | 一个普通的类 | 上下文环境,持有 Stragegy 的引用 |
策略模式简单的 UML
一、曹操败走华荣道
咱们知道三国演义中曹操败走华容道的故事,相传在赤壁之战以后,曹操的船舰被刘备烧了,曹操逃离时面前有两条路:一、平坦的大路。二、泥泞的华容道。面对这两条路,曹操没有选择大路而选择有炊烟的小路「华容道路」,理由---实则虚之,虚则实之,那么曹操在选择道路的时候其实就是选择策略
败走华容道的简单的 UML
根据 UML 编码
/** * 抽象的策略,定义逃跑路线 */ public interface IRunStrategy { // 逃跑线路 void escapeRoute() ; }
/** * 具体的策略一走大路 */ public class Highroad implements IRunStrategy { @Override public void escapeRoute() { System.out.println("走大路"); } }
/** * 具体的策略二走华容道 */ public class HuaRongRoad implements IRunStrategy { @Override public void escapeRoute() { System.out.println("走华容道"); } }
/** * 上下文 持有 IRunStrategy 的引用 */ public class ContextRunStrategy { private IRunStrategy iRunStrategy ; public ContextRunStrategy(IRunStrategy iRunStrategy){ this.iRunStrategy = iRunStrategy ; } /** * 选择道路 */ public void choiceRoad(){ iRunStrategy.escapeRoute(); } }
/** * 曹操选择路线 */ public class CaoCao { public static void main(String args[]){ /** * 曹操疑心重,选择了华容道,对曹操来讲至于杂样走华容道,不关心,死多少人也不关心,只关心我要走这条道就好 */ IRunStrategy huaRongRoad = new HuaRongRoad() ; ContextRunStrategy contextRunStrategy = new ContextRunStrategy(huaRongRoad) ; contextRunStrategy.choiceRoad(); } }
真的走了华容道,好吧 no zuo no die ,咱们能够看到上面曹操选择逃跑路线都是行为,因此很适合策略模式「策略模式就是一种选择模式,当你犹豫不定的时候就使用策略模式」
注意: 策略的核心不是如何实现算法,而是如何更优雅的把这些算法组织起来,让客户端很是好调用「虽然策略很是多,能够自由切换,可是同一时间客户端只能调用一个策略,其实也很好理解,你不可能同时既坐飞机,又坐火车」。
二、出行旅行方式
通过上面的曹操败走华荣道,咱们对策略有了感受了吧,那么下来咱们趁热打铁,再来一发,咱们都知道出去旅行通常方式:坐飞机、坐火车、坐大巴、自驾游等等,这一个个的出行方式就是策略,接下来我给出简单的 UML 图,代码部分请各自自行实现「道理都懂,你的生活质量仍是没有提升,方法再多也不见有多成功,就是由于实践太少,动手才是真理,靠--忘记吃药了,脉动回来」
出行方式简单的 UML
代码实现
你们根据出行的 UML 图实现代码便可「很是简单,相信均可以实现」
三、Android 中使用策略场景
段子来了
先看个段子,轻松一下「注如下只是一个简单举例,库不分前后,俗话说没有最好,只有最适合」
相信作 Android 的朋友都离不开网络请求,有一天你「小明」发现了一个传说中很好的网络请求库 AsyncHttpClient ,你高兴的把网络请求相关的 API 都实现了,经理看到了说不错不错,写的很快吗,忽然有一天,经理说:小明 AsyncHttpClient 好多 API 过期了「随着 Android 版本的更新」,而且对 RestFul 支持的不太友好,我看到一个叫 Retorfit2「据说是最好的网络」 的库,默认支持 OkHttp ,用 Retorfit 把 AsyncHttpClient 替换了吧,很是简单对你来讲,小明这时估计内心飘过了一千匹羊驼「我靠,为麻不早说」,又过了一些时间,经理又说,小明呀,Volley 是 Google 推荐的网络请求库,你换成 Volley 库吧,小明此时估计把经理的八辈祖宗都问候了一遍,又是一通加班加点的改,最后 Happy 的改好了。后面又有一个牛 B 的库,经理又让替换,小明哭了「为何受伤的老是我」...
看到这里你们应该想到了,上面的请求场景就是一个个的策略,若是小明按照策略模式走下来,只是添加扩展子策略,压根原来的方法毛都不用改,只能说,小明呀,你可张点心吧。
MVP + 策略模式
下面咱们使用 MVP + 策略模式模拟一个简单的登陆功能,实现上面小明的需求
MVP+retorfit+rx 请求策略简单的 UML
根据 UML 撸码
首先咱们要使用 AsyncHttpClient、Retorfit 等,先添加配置 Gradle「项目 Module 的 build.grade中」
compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'io.reactivex.rxjava2:rxjava:2.1.5' compile 'com.loopj.android:android-async-http:1.4.9'
注: 如下代码纯粹是为了演示策略模式,顺手写的,好多细节可能没有考虑到,可是基本框架就是这样的,能够自行完善
/** * @Description MVP 中的 Presenter 基 * @Creator TigerChain(建立者) */ public interface Presenter { }
/** * @Description MVP 中的 Model 基类 * @Creator TigerChain(建立者) */ public interface Model { }
/** * @Description MVP 中的 View 基类 * @Creator TigerChain(建立者) */ public interface IView { }
ILoginContact.java
「固然也能够不写此类,直接写登陆 MVP 的直接子类」package designpattern.tigerchain.com.mvphttpstrategy.mvp; import designpattern.tigerchain.com.mvphttpstrategy.mvp.domain.User; import io.reactivex.Observable; /** * @Description MVP 的关联类「也能够单首创建 MVP 就是有点乱」 * @Creator TigerChain(建立者) */ public interface ILoginContact { interface LoginView extends IView{ //显示进度条 void showProgress() ; //隐藏进度条 void hideProgress() ; //登陆成功 void loadSuccess(String str) ; //登陆失败 void loadFailed(String str) ; //取得用户名 String getUserName() ; //取得用户密码 String getUserPass() ; //清除输入框 void clearEditText() ; //用户名和密码不能为空 void editnotNull() ; } interface LoginPresenter extends Presenter{类 /** * 登陆功能 */ void login() ; /** * 清除输入框架内容 */ void clear() ; } interface ILoginModel extends Model{ /*** * 登陆的方法,其实这里就是一个抽象策略,至于你使用 retrofit 仍是 asynchttpClient 仍是 Volley 那是本身的事情 * @param uName * @param uPass * @return */ Observable<User> login(String uName, String uPass) ; } }
其中 ILoginModel 就是一个抽象策略,这里是登陆功能
具体策略1:使用 AsyncHttpClient 调用登陆
/** * @Description 具体策略使用 AsyncHttpClient 来调用登陆 API * @Creator TigerChain(建立者) */ public class AsynchHppClientImplLogimModel implements ILoginContact.ILoginModel { @Override public Observable<User> login(final String uName, final String uPass) { return Observable.create(new ObservableOnSubscribe<User>() { @Override public void subscribe(final ObservableEmitter<User> e) throws Exception { AsyncHttpClient client = new AsyncHttpClient() ; // 这里就是一个请求 没有真正的对接服务器,只是一个演示 client.get("http://www.baidu.com", new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { if(uName.equalsIgnoreCase("TigerChain") && uPass.equals("123")){ User user = new User() ; user.setuName(uName); user.setUpass(uPass); e.onNext(user); e.onComplete(); }else{ e.onNext(null); e.onComplete(); } } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { e.onError(error); } }) ; } }); } }
具体策略2:使用 Volley 调用登陆 API
/** * @Description 具体策略使用 Volley 实现登陆功能 * @Creator TigerChain(建立者) */ public class VolleyImplLoginModel implements ILoginContact.ILoginModel { @Override public Observable<User> login(final String uName, final String uPass) { return Observable.create(new ObservableOnSubscribe<User>() { @Override public void subscribe(final ObservableEmitter<User> e) throws Exception { /*** * 这里调用和 Volley 相关的 API 实现登陆便可 */ } }); } }
具体策略3:使用 RetorFit 调用登陆 API
/** * @Description 具体策略 使用 RetorFit 实现登陆功能性 * @Creator TigerChain(建立者) */ public class RetorFitImplLoginModel implements ILoginContact.ILoginModel { @Override public Observable<User> login(final String uName, final String uPass) { Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://") .build(); ILoginRetorfitApi loginService = retrofit.create(ILoginRetorfitApi.class) ; return loginService.login(uName,uPass) ; } }
其中 User 和 ILoginRetorfitApi 类分别是:
# User.java /** * @Description 普通人的 Java * @Creator TigerChain(建立者) */ public class User { private String uName ; private String Upass ; public String getuName() { return uName; } public void setuName(String uName) { this.uName = uName; } public String getUpass() { return Upass; } public void setUpass(String upass) { Upass = pass; } }
# ILoginRetorfitApi.java /** * @Description Retrofit API * @Creator TigerChain(建立者) */ public interface ILoginRetorfitApi { @GET("/login") Observable<User> login( @Field("userName") String userName, @Field("passWord")String passWord) ; }
/** * @Description MVP 中的P ,就至关于策略中Context * @Creator junjun(建立者) */ public class LoginPresenterImpl implements ILoginContact.LoginPresenter { private ILoginContact.ILoginModel iLoginModel ; private ILoginContact.LoginView loginView ; public LoginPresenterImpl(ILoginContact.LoginView loginView,ILoginContact.ILoginModel iLoginModel){ this.iLoginModel = iLoginModel ; this.loginView = loginView ; } @Override public void login() { String uName = loginView.getUserName() ; String uPass = loginView.getUserPass() ; if(TextUtils.isEmpty(uName) || TextUtils.isEmpty(uPass)){ loginView.editnotNull(); return ; } loginView.showProgress(); iLoginModel.login(uName,uPass) // subscribeOn(Schedulers.io()) 因为 AsyncHttpClient 自己就是在子线程去请求的,因此这里为了演示把这个去掉 .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<User>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(User user) { loginView.loadSuccess("登陆成功"); } @Override public void onError(Throwable e) { loginView.loadFailed("用户名或密码错误,登陆失败"); loginView.hideProgress(); } @Override public void onComplete() { loginView.hideProgress(); } }) ; } @Override public void clear() { loginView.clearEditText(); } }
到此为止,咱们的 MVP+RX+Retorfit 带策略的登陆功能就完成了。
下面来看客户调用,不贴代码了「放一张部分代码截图」,后面放出所有 DEMO 你们自行查看
怎么样,经过以上几个例子,相信咱们对策略模式有了很好的理解了
demo 没有实现完毕,其中 Retorfit 和 Volley 没有完善,有兴趣的能够自行完善
Demo 地址:https://github.com/githubchen001/mvp-rx-loginStrategy
一、TimeInterpolator 时间插值器
作过动画的朋友都知道,插值器的概念,一句话就是:设置不一样的插值器,动画能够以不一样的速度模型来执行
先看看 TimeInterpolator 和它的直接子类
TimeInterpolator 的 UML
从 UML 图就能够看出 TimeInterpolator 是一个典型的策略模式,你想使用那种插件器,是客户端的事情,而且结合工厂模式建立各自的插件器
二、ListAdapter
乍一看好像没有见过这个东东呀,可是我说一个你确定知道 ListView 知道吧,BaseAdapter「实现了 ListAdapter」 知道吧 ,你们之前确定都使用过 ListView 「虽然如今推荐使用 RecyclerView ,可是它依然被不少人使用」,它就是一个策略,咱们来分析一下
ListAdaper 和它的直接子类
ListAdapter 的简单的 UML
以上只是 ListAdapter 简单的一个 UML 图「问题说明便可,真正的 ListAdapter 比这复杂多」,从上面能够看到 ListAdapter 典型的一个策略模式,有兴趣的朋友能够自行跟一下源码
三、RecyclerView.LayoutManager
RecyclerView.LayoutManager 和它的子类
RecyclerView.LayoutManager 简单的 UML
能够看到 RecyclerView.LayoutManager 也是一个策略模式
其实不知不觉中咱们使用了好多策略模式,只是没有注意罢了,细细想一想,是否是那么回事,再多例子再也不举了。有兴趣的朋友能够自已去扒扒 Android 源码看看那部分使用的是策略模式
策略模式和简单工厂很是类似,结构基本上同样,可是它们侧重点不同
可是咱们在策略模式中可使用简单工厂模式「把生成策略这一过程使用工厂去实现,这样好很差呢?适合就是最好的」
既然策略模式使用这么普遍,那么策略模式是否是就是无敌了呢,没有一点点缺点?确定不是的。
优势:
缺点:
到此为止咱们简单明了的介绍完了策略模式,最后说一下:点赞是一种美德