写在之前

这周生活上出现了很多的不如意,从周一开始就觉得哪里出现了问题,然后就是各种烦躁的情绪,后来事情还真是如预感的那样发生了,很是心痛,但也无可奈何,希望大家都好好珍惜自己身边的人:友人,亲人,家人,愿一切和睦。

正文

一直以来都饱受公司APP客户端关于各种计费点的折磨。一段时间内,同一应用或不同应用间接入多家的计费模式,然后需要在不同的计费间来回的跳转,大大的增加了出错的几率,甚至有时候出现计费点错乱的现象,这就导致了工作效率的降低,而且做了大量的无用功,费时费力还没有成果。

基于这种困扰,一直以来都想封装一套统一实现计费策略的代码库,但是一直没有着手去做。最近有一套APP要实现微信,支付宝支付等计费,那么正好可以利用这个机会来实现一整套的计费点代码库。

而本篇博文的产生就是计费代码库的一个缩影,主要讲解的是如何使用策略模式设计这种可以使用多种算法来完成同样的目标。

需求分析

下面来简单的看下需求:

本款APP要求能实现微信、支付宝等支付方式进行购买虚拟币,购买完成后需上传购买数量,同时要更新用户所拥有的虚拟币。

ok,我们来分析下需求,主要可以分三步:

首先,购买虚拟币,这是一个动作,在这个动作中有可以分为多种形式,比如这里的用微信和支付宝购买;

其次,购买完成后,要上传服务端存储用户购买的虚拟币数量;

最后是更新UI,显示用户目前拥有的虚拟币。

由上面的分析,我们对需求有了很清晰的认识,这里的主要任务是设计一个简版的计费代码库,所以我们主要关心的也就是计费这一模块,其他的部分我们并不能考虑到计费库里,我相信大家都能明白,一个库,干好一件事即可。

说到计费,我们的需求中也就是购买虚拟币,而购买虚拟币这个行为可以是多种形式的,比如说使用微信,支付宝等,那么各种支付方式是不是都是一样的实现呢?

显然不是,它们都有自己的实现方式,而且每一家也都有自己的计费流程等,所以我们的库设计应该是可以符合多种实现的计费模式,并且能很好的实现扩展,而且各种实现可以互相替换,比如,购买虚拟币能使用微信支付也能使用支付宝支付,这就实现了互相替换。那么有没有这么一种实现方式呢?

显然答案是有的,这就是我们要讲的策略模式。

模式定义

那到底什么是策略模式呢?

策略模式是定义了一族算法,并分别将每组算法封装起来,使它们之间可以互相替换。算法的变化独立于使用算法的用户。

它主要使用在哪些场景呢?

①:同一种行为,多种实现。

②:安全地封装多种同一类型的操作。

③:同一抽象类有多个子类,而又需要选择具体子类操作。

由它的定义和使用场景,我们更加确信了我们的计费代码库使用这种模式是行得通的。

那么,我们到底该怎么使用策略模式进行设计我们的库呢?

详细设计

说道关于计费的问题,相信我们每个人都很清楚的了解,那就是需要有一个类似pay的方法专门用来进行支付,所以我们得有一个支付类,并且这个支付类带有一个pay的支付方法,如下设计:

这里我并没有针对参数来进行详细的构建,毕竟只是一个针对简单的demo级别库,主要还是用来学习策略模式的,所以,我这里就只是简单的设计一个String类型的url参数,并让他返回一个String类型的结果,因为大多数网络请求都是返回的一个json串,便于解析。

可以看到我在这里设计了一个基类BasePay,并带有一个pay方法,接过相信支付功能的同学都应该知道,为了保证支付的安全性,很多支付渠道都会有一个预订单的接口,在预订单中返回一些重要的信息,并在支付接口中调用,例如微信支付就是这样模式。

所以为了满足这种需求,我们就需要有这么一个预订单的方法,那么我们在我们的基类中添加上这种方法:

同样的没有做过多的参数考虑,只是让他传进一个String类型的URL地址。

ok,我们的基类已经设计出来了,那么各种各种的支付都可以继承此类来完成预订单和支付的能力,那么你觉得这样的设计怎么样呢?

假如有一种支付是不需要预订单呢?

这样也很简单,我就直接做一个空的实现。

没错,这种可以实现,那接入有100个支付,其中有80个没有预订单的实现呢?

难道你要做上80个空实现吗?

显然这是不可取的,那么我们该怎么做呢?

设计原则:保持共性,封装变化

假如有80个支付渠道不需要预订单,20个是需要预订单的,由此可以看出这个预订单的接口是变化的,而且剩下的20个需要预定单的每个实现也是不相同的,那么我们根据面向对象的设计原则:把需要变化的部分给独立的封装起来,只保留相同的部分,那么我们是不是可以把它给独立的封装起来以便应付随时变化的实现呢?

同样的道理支付接口的实现也是不尽相同的,是否也应该封装起来呢?

由此想到了另外的一个设计原则。

设计原则:针对接口编程,而不是针对实现编程

针对接口编程,不针对具体的实现进行编程,这样我们就可以区分不同的实现独立的完成,同时每个支付的业务只面对接口,不用关心具体的实现是怎么完成的:

由上图所示,分别的定义了两个接口PreOrderInterface和PayInterface,并分别包含一个方法,并且我们分别对这两个接口做了两个实现,分别是针对微信和支付宝的。

这样一来的话,我们就把原来的BasePay里面的两个变化的方法分别的抽取出来封装成接口,并根据不同的业务渠道进行实现。

那我们是不是可以直接用BasePay基类来实现这个两个接口呢?

如果直接用BasePay来实现接口,那和不抽取变化封装有什么区别呢,所以我们不能直接用BasePay来或者是它的子类来直接的实现这两个接口,那么到底该怎么运用这两个接口呢?

由此我们想到了另外的一种设计原则:

设计原则:少用继承,多用组合

可以使用组合的形式来添加对接口的运用,有了接口的引用,不仅可以包含了算法的封装,同时也可以在运行时动态的改变行为。

这样我们就有了对这两个接口的引用,那么我们在定义两个对接口调用的方法:

同时为了便于扩展,为了能在运行时改变我们的行为方式,我们可以用设置接口的方式来实现:

ok,这样将会更加利于我们的扩展。下面来看看完整的BasePay类吧:

这样的话,当我们需要预订单的时候直接的调用performPreOrder方法,在支付的时候调用performPay方法,可以完全的不用考虑它的直接实现到底是怎么做的,我们只需要关心的就是调用的接口而已,从而降低了耦合性。

当然这只是我们的基类,我们还需要它的具体实现类:

如果具体类有相同的功能,那么可以在父类中定义一个抽象方法,同时改变父类为抽象类,那么这个相同的功能就可以直接的在子类中实现,比如说要打印一个输出支付结果的log日志,那么就可以分别在子类中完成。

ok,有了子类具体实现,那么到底该怎么使用呢:

其实也很简单,既然父类已经有了对接口的引用,那么我们可以在子类中对接口实例化:

这里可以看出,当我们需要什么的时候就进行什么初始化,如果不需要,可以直接的不用管它。

那么在来看看我们是怎么使用的:

当我们确定要使用哪种支付方式时,可以利用面向对象多态的特性指定具体的子类,然后在子类中实例化父类对接口的具体引用实现,当使用支付接口时,可以直接的调用父类提供的支付方法完成支付。

父类只需要关心引用的接口,而不需要关心具体的接口实现,实现解耦;

子类只需要关系对父类引用接口的实例化,和所共有的特性实现,也不需要具体的实现;

对具体的实现进行了封装,每种具体的实现类都实现接口,它只关注具体的实现,这样就把整个变化封装在特有的实现类中,通过接口获取到对它的引用,那么整个结构就显得非常的清晰,各个模块都只需要关注自己的领域,而且模块间耦合性也降到最低。

把变化进行封装,保持共性,通过接口制定具体的算法,这就是我们的策略模式。

最后在来看下整个类图:

ok,这样我们就利用策略模式实现了一个简单的计费代码库,每当有新的计费加入时,我们只需要添加具体的实现类和具体的支付类,并不需要修改原来的代码,并且可以多方面复用。

到这里基本的策略模式就讲完了,计费代码库demo级也就出来了,当然它并不完善,只是关注策略模式的这一部分,其他的像网络请求,一些帮助类等都是需要封装的,也不是这个主题所关注的,所以这就需要大家根据自己的需求来实现了。

好了,今天就讲到这里吧。

各位如果还有哪里不明白的,或是我这里讲的还不够透彻,亦或是讲错了的地方请留言指正,让我们共同进步,谢谢

同时,请大家扫一扫关注我的微信公众号,虽然写的不是很勤,但是每一篇都有质量保证,让您学习到真正的知识。

Android 设计模式实战之关于封装计费代码库的策略模式详谈的更多相关文章

  1. Java8 in action(1) 通过行为参数化传递代码--lambda代替策略模式

    [TOC] 猪脚:以下内容参考<Java 8 in Action> 需求 果农需要筛选苹果,可能想要绿色的,也可能想要红色的,可能想要大苹果(>150g),也可能需要红的大苹果.基于 ...

  2. javascript设计模式与开发实践阅读笔记(5)——策略模式

    策略模式:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 我的理解就是把各种方法封装成函数,同时存在一个可以调用这些方法的公共函数.这样做的好处是可以消化掉内部的分支判断,使代码效率 ...

  3. 两种语言实现设计模式(C++和Java)(三:策略模式)

    策略模式是指定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化.也就是说这些算法所完成的功能一样,对外的接口一样,只是各自实现上存在差异.用策略模式 ...

  4. 计算器软件的代码实现 (策略模式+asp.net)

    一 策略模式代码的编写 using System; using System.Collections.Generic; using System.Linq; using System.Web; /// ...

  5. Android使用的设计模式2——策略模式

    今天讲解一下策略模式,策略模式也是很常用的设计模式,对多种算法或者数据结构选择使用的情况下,经常会使用策略模式来管理这些算法.下面会简单讲解一下策略模式的概念和基本实现.然后结合Android里面的实 ...

  6. Android设计模式—策略模式

    1.策略模式概念 定义一系列算法,把他们独立封装起来,并且这些算法之间可以相互替换.策略模式主要是管理一堆有共性的算法,客户端可以根据需要,很快切换这些算法,并且保持可扩展性. 策略模式的本质:分离算 ...

  7. Android项目实战--手机卫士开发系列教程

    <ignore_js_op> banner131010.jpg (71.4 KB, 下载次数: 0) 下载附件  保存到相册 2 分钟前 上传   Android项目实战--手机卫士01- ...

  8. 《大话设计模式》ruby版代码:策略模式

    需求: 商场收银软件,根据客户购买物品的单价和数量,计算费用,会有促销活动,打八折,满三百减一百之类的. 一,使用工厂模式. # -*- encoding: utf-8 -*- #现金收费抽象类 cl ...

  9. 学C#之设计模式系列笔记(1)策略模式

    一.借鉴说明 1.<Head First Design Patterns>(中文名<深入浅出设计模式>) 2.维基百科,策略模式,https://zh.wikipedia.or ...

随机推荐

  1. mysql sql语句

    1.数据库和表的操作 创建 create修改 alter删除 drop查看 show 1.1创建数据库 CREATE DATABASE [IF NOT EXISTS] db_name    [crea ...

  2. 百度地图API,定位您的当前位置

    1.介绍 利用百度地图的API来定位您的所属位置,这个位置返回的是经纬度,而不是具体的汉字位置.利用经纬度,再显示在百度地图上的位置. 2.代码 <html> <head> & ...

  3. hammer的初始化及移动端各种滑动

    前言:本人对hammer了解不是很多,早做项目时遇到了手机端的一些滑动事件,特此分析下hammer的某些属性. hammer.js是一款开源的移动端脚本框架,他可以完美的实现在移端开发的大多数事件,如 ...

  4. Visual Studio for Mac 初体验

    你喜爱的 IDE,现在可用于 Mac 来自:https://www.visualstudio.com/zh-hans/vs/visual-studio-mac/ 惊不惊喜?意不意外?惊喜但不意外,因为 ...

  5. 写给Android App开发人员看的Android底层知识(1)

    这个系列的文章一共8篇,我酝酿了很多年,参考了很多资源,查看了很多源码,直到今天把它写出来,也是战战兢兢,生怕什么地方写错了,贻笑大方. (一)引言 早在我还是Android菜鸟的时候,有很多技术我都 ...

  6. Vulkan Tutorial 开发环境搭建之Windows

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 相信很多人在开始学习Vulkan开发的起始阶段都会在开发环境的配置上下一些功夫,那么 ...

  7. swift pod第三方OC库使用use_frameworks!导致#import提示无法找到头文件

    以MBProgressHUD为例子 swift中Podfile文件一般都会加上use_frameworks! 这样就可以直接通过import MBProgressHUD来访问MBProgressHUD ...

  8. PHP 工厂模式 实例讲解

    简单工厂模式:①抽象基类:类中定义抽象一些方法,用以在子类中实现②继承自抽象基类的子类:实现基类中的抽象方法③工厂类:用以实例化对象 看完文章再回头来看下这张图,效果会比较好 1 采用封装方式 2 3 ...

  9. javaWeb学习总结(3)- 通过Servlet生成验证码图片(2)

    一.BufferedImage类介绍 生成验证码图片主要用到了一个BufferedImage类,如下:

  10. JS Event事件流(冒泡机制、捕获机制、事件绑定)

    1.事件流 事件流:从页面中接收事件的顺序.也就是说当一个事件产生时,这个事件的传播过程,就是事件流. IE的事件流 IE中的事件流叫事件冒泡:事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播 ...