钦州房产网站建设,石家庄建设工程信息网官网,网站文章伪原创怎么做,东莞建设网站推广公司地址场景App 的支付流程#xff0c;添加多种支付方式#xff0c;不同的支付方式#xff0c;对应的操作不一样#xff0c;有的会跳转到一个新的webview#xff0c;有的会调用系统浏览器#xff0c;有的会进去一个新的表单页面#xff0c;等等。并且可以添加的支付方式也是不确…场景App 的支付流程添加多种支付方式不同的支付方式对应的操作不一样有的会跳转到一个新的webview有的会调用系统浏览器有的会进去一个新的表单页面等等。并且可以添加的支付方式也是不确定的由后台动态下发。如下图所示根据上图 ui 理一下执行流程1. 点击不同的添加支付方式 item。2. 进入相对应的添加支付方式流程表单页面、webview、弹框之类的。3. 在第三方回调里面根据不同的支付方式执行不同的操作。4. 调用后台接口查询添加是否成功。5. 根据接口结果展示不同的成功或者失败的ui。以前的实现方式用一个 Activity 承载上述所有的流程都在 Activity 中。Activity 包含了列表展示、多种支付方式的实现和 ui。伪代码如下class AddPaymentListActivity : AppCompatActivity(R.layout.activity_add_card) {private val addPaymentViewModel : AddPaymentViewModel ...override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)addPaymentViewModel.checkPaymentStatusLiveData.observer(this) { isSuccess -// 从后台结果判断是否添加成功if (isSuccess) {addCardSuccess(paymentType)} else {addCardFailed(paymentType)}}}private fun clickItem(paymentType: PaymentType) {when (paymentType) {PaymentType.ADD_GOOGLE_PAY - //执行添加谷歌支付流程PaymentType.ADD_PAY_PEL- //执行添加PayPel支付流程PaymentType.ADD_ALI_PAY- //执行添加支付宝支付流程PaymentType.ADD_STRIPE- //执行添加Stripe支付流程}}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)when (resultCode) {PaymentType.ADD_GOOGLE_PAY - {// 根据第三方回调的结果拿到key// 根据key调用后台的Api接口查询是否添加成功}PaymentType.ADD_PAY_PEL - // 同上// ...}}private fun addCardSuccess(paymentType: PaymentType){when (paymentType) {PaymentType.ADD_GOOGLE_PAY - // 添加对应的支付方式成功展示成功的ui然后执行下一步操作PaymentType.ADD_PAY_PEL- // 同上// ...}}private fun addCardFailed(paymentType: PaymentType){when (paymentType) {PaymentType.ADD_GOOGLE_PAY - // 添加对应的支付方式失败展示失败的uiPaymentType.ADD_PAY_PEL- // 同上// ...}}enum class PaymentType {ADD_GOOGLE_PAY, ADD_PAY_PEL, ADD_ALI_PAY, ADD_STRIPE}}虽然看起来根据 paymentType 来判断逻辑条理也还过得去但是实际上复杂度远远不止如此。• 不同的支付方式跳转的页面相差很大。• 结果的回调获取也相差很大并不是所有的都在onActivityResult中。• 成功和失败实际上也不能统一来处理里面包含很多的if...else...判断。• 如果支付方式是后台动态下发的处理起来判断逻辑就更多了。此外最大的问题扩展性问题。当新来一种支付方式例如微信支付之类的改动代码就很大了基本就是将整个Activity中的代码都要改动。可以说上面这种方式的可扩展性为零就是简单的将代码都揉在一起。优化后的代码要想实现高内聚低耦合最简单的就是套用常见的设计模式回想一下发现策略模式简单工厂模式非常这种适合这种场景。先看下优化后的代码class AddPlatformActivity : BaseActivity() {private var addPayPlatform: IAddPayPlatform? nullprivate fun addPlatform(payPlatform: String) {// 将后台返回的支付平台字符串变成枚举类val platform: PayPlatform getPayPlatform(payPlatform) ?: returnaddPayPlatform AddPayPlatformFactory.getCurrentPlatform(this, platform)addPayPlatform?.getLoadingLiveData()?.observe(thisAddPlatformActivity) { showLoading -if (showLoading) startLoading() else stopLoading()}addPayPlatform?.addPayPlatform(AddCardParameter(platform))}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)// 将onActivityResult的回调转接到需要监听的策略类里面addPayPlatform?.thirdAuthenticationCallback(requestCode, resultCode, data)}
}策略模式意图 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。主要解决 在有多种算法相似的情况下使用if...else所带来的复杂和难以维护。何时使用 一个系统有许多许多类而区分它们的只是他们直接的行为。如何解决 将这些算法封装成一个一个的类任意地替换。关键代码 实现同一个接口。优点 1、算法可以自由切换。2、避免使用多重条件判断。3、扩展性良好。缺点 1、策略类会增多。2、所有策略类都需要对外暴露。使用场景 1、如果在一个系统里面有许多类它们之间的区别仅在于它们的行为那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。2、一个系统需要动态地在几种算法中选择一种。3、如果一个对象有很多的行为如果不用恰当的模式这些行为就只好使用多重的条件选择语句来实现。需要实现的目标解耦宿主 Activity现在宿主Activity中代码太重了包含多种支付方式实现还有列表ui的展示网络请求等。现在目标是将 Activity 中的代码拆分开来让宿主 Activity 变得小而轻。如果产品说新增一种支付方式只需要改动很少的代码就可以轻而易举的实现。抽取成独立的模块因为公司中有可能存在多个项目支付模块的分层应该处于可复用的层级以后很有可能将其封装成一个独立的 mouble给不同的项目使用。现在代码全在 Activity 中以后若是抽取 mouble 的话相当于整个需求重做。组件黑盒组件黑盒这个名词是我自己的一个定义。大致意思将一个 View 或者一个类进行高度封装尽可能少的暴露public方法给外部使用自成一体。业务方在使用时可以直接黑盒使用某个业务组件不必关心其中的逻辑。业务方只需要一个简单的操作例如点击按钮调用方法然后逻辑都在组件内部实现组件内处理外部事件的所有操作例如Loading、请求网络、成功或者失败。业务方都不需要知道组件内部的操作做到宿主和组件的隔离。当然这种处理也是要分场景考虑的其中一个重点就是这个组件是偏业务还是偏功能也就是是否要将业务逻辑统一包进组件想清楚这个问题后才能去开发一个业务组件。 因为添加支付方式是一个偏业务的功能我的设计思路是外部 Activity 点击添加对应的支付方式将支付方式的枚举类型和支付方式有关的参数通过传递然后不同的策略类组件执行自己的添加逻辑再通过一层回调将第三方支付的回调从 Activity 中转接过来每个策略类内部处理自己的回调操作具体的策略类自己维护成功或者失败的ui。具体实现定义顶层策略接口interface IAddPayPlatform {fun addPayPlatform(param: AddCardParameter)fun thirdAuthenticationCallback(requestCode: Int?, resultCode: Int?, data: Intent?)fun addCardFailed(message: String?)fun addCardSuccess()
}通用支付参数类open class AddCardParameter(val platform: PayPlatform)class AddStripeParameter(val card: Card, val setPrimaryCard: Boolean, platform: PayPlatform): AddCardParameter(platform PayPlatform.Stripe)因为有很多种添加支付方式不同的支付方式对应的参数都不一样。所以先创建一个通用的卡片参数基类AddCardParameter, 不同的支付方式去实现不同的具体参数。这样的话策略接口就可以只要写一个添加卡片的方法addPayPlatform(param: AddCardParameter)。Loading 的处理因为我想实现的是黑盒组件的效果所有添加卡片的loading也是封装在每一个策略实现类里面的。Loading的出现和消失这里有几种常见的实现方式• 传递BaseActivity的引用,因为我的loading有关的方法是放在BaseActivity中这种方式简单但是会耦合BaseActivity。• 使用消息事件总线例如EventBus之类的这种方式解耦强但是消息事件不好控制还要添加多余的依赖库。• 使用LiveData在策略的通用接口中添加一个方法返回Loading的LiveData, 让宿主Activity自己去实现。interface IAddPayPlatform {// ...fun getLoadingLiveData(): LiveDataBoolean?
}提取BaseAddPayStrategy因为每一个添加卡的策略会存在很多相同的代码这里我抽取一个BaseAddPayStrategy来存放模板代码。需要实现黑盒组件的效果宿主Activity中都不需要去关注添加支付方式是不是存在网络请求这一个过程所以网络请求也分装在每一个策略实现类里面。abstract class BaseAddPayStrategy(val activity: AppCompatActivity, val platform: PayPlatform) : IAddPayPlatform {private val loadingLiveData SingleLiveDataBoolean()protected val startActivityIntentLiveData SingleLiveDataIntent()override fun getLoadingLiveData(): LiveDataBoolean loadingLiveDataprotected fun startLoading() loadingLiveData.setValue(true)protected fun stopLoading() loadingLiveData.setValue(false)private fun reloadWallet() {startLoading()// 添加卡片完成后重新刷新钱包数据}override fun addCardSuccess() {reloadWallet()}override fun addCardFailed(message: String?) {stopLoading()if (isEWalletPlatform(platform)) showAddEWalletFailedView() else showAddPhysicalCardFailedView(message)}/*** 添加实体卡片失败展示ui*/private fun showAddPhysicalCardFailedView(message: String?) {showSaveErrorDialog(activity, message)}/*** 添加实体卡片成功展示ui*/private fun showAddPhysicalCardSuccessView() {showCreditCardAdded(activity) {activity.setResult(Activity.RESULT_OK)activity.finish()}}private fun showAddEWalletSucceedView() {// 添加电子钱包成功后的执行activity.setResult(Activity.RESULT_OK)activity.finish()}private fun showAddEWalletFailedView() {// 添加电子钱包失败后的执行}// ---默认空实现有些支付方式不需要这些方法---override fun thirdAuthenticationCallback(requestCode: Int?, resultCode: Int?, data: Intent?) Unitoverride fun getStartActivityIntent(): LiveDataIntent startActivityIntentLiveData
}具体的策略类实现通过传递过来的AppCompatActivity引用获取添加卡片的ViewModel实例AddPaymentViewModel,然后通过AddPaymentViewModel去调用网络请求查询添加卡片是否成功。class AddXXXPayStrategy(activity: AppCompatActivity) : BaseAddPayStrategy(activity, PayPlatform.XXX) {protected val addPaymentViewModel: AddPaymentViewModel by lazy {ViewModelProvider(activity).get(AddPaymentViewModel::class.java)}init {addPaymentViewModel.eWalletAuthorizeLiveData.observeState(activity) {onSuccess { addCardSuccess()}onError { addCardFailed(it.detailed) }}}override fun thirdAuthenticationCallback(requestCode: Int?, resultCode: Int?, result: Intent?) {val uri: Uri result?.data ?: returnif (uri.host www.xxx.com) {uri.getQueryParameter(transactionId)?.let {addPaymentViewModel.confirmEWalletAuthorize(platform.name, it)}}}override fun addPayPlatform(param: AddCardParameter) {startLoading()addPaymentViewModel.addXXXCard(param)}
}简单工厂进行优化因为我不想在Activity中去引用每一个具体的策略类只想引用抽象接口类IAddPayPlatform, 这里通过一个简单工厂来优化。object AddPayPlatformFactory {fun setCurrentPlatform(activity: AppCompatActivity, payPlatform: PayPlatform): IAddPayPlatform? {return when (payPlatform) {PayPlatform.STRIPE - AddStripeStrategy(activity)PayPlatform.PAYPAL - AddPayPalStrategy(activity)PayPlatform.LINEPAY - AddLinePayStrategy(activity)PayPlatform.GOOGLEPAY - AddGooglePayStrategy(activity)PayPlatform.RAPYD - AddRapydStrategy(activity)else - null}}
}再增加一种支付方式如果再增加一种支付方式宿主Activity中的代码都可以不要改动只需要新建一个新的策略类实现顶层策略接口即可。这样不管是删除还是新增一种支付方式维护起来就很容易了。策略模式的好处就显而易见了。