首页 > 其他分享 >iOS 微信、支付宝、银联支付组件的进一步设计

iOS 微信、支付宝、银联支付组件的进一步设计

时间:2023-06-23 10:34:21浏览次数:47  
标签:end 微信 void iOS payType API 银联 支付 组件

原文地址:https://zhanglei.blog.csdn.net/article/details/121376500

前言

有段时间没写技术文章了,一是因为工作太忙,再者因为本人文笔实在一般。最近终于闲下来,本着分享的目的将一些组件设计上的心得与大家分享。
本篇文章是基于原有一篇关于支付文章的进一步优化设计,所以在阅读本篇文章前还是建议先移步到那篇文章。
文章地址: 微信、支付宝、银联、Paypal 支付组件封装

描述

在封装支付接口时,需要面临各支付平台不同SDK集成的问题,有的支付第三方平台只通过sdk组件就可完成支付,像支付宝,但大部分的支付第三方平台需要先去调用服务端API接口获取支付需要的信息,拿到这些支付信息后,再去调用sdk组件完成支付,这类第三方有银联(需要获取tn交易流水号),微信(需要获取prepayData)等。

为了以后的支付功能复用,想要设计一个支付组件,该组件整合并统一了这些第三方支付sdk的接口,以便给客户端快速集成。在设计支付组件的过程中就遇到上面提到的问题。 如何解决某些第三方需要请求一些数据后,再进行支付的问题 ? 试想一下如果将这些请求hardcode到组件中,显然能满足当前的功能,局限性也非常明显,只能适用当前的支付业务。 此时的支付组件会和网络组件藕合,不利于扩展及复用。

设计

如何解藕? 如何能让这些需要请求API的第三方不污染组件? 解藕的思想就是“抽离变化,并封装”。 我们需要把不稳定的部分抽离出来,使其独自变化,不影响稳定的部分。 找到了方向, 如何抽离? 这里我们可以使用面向协议的编程的思想,将请求API的行为进行抽象。
伪代码:

//抽像一个协议, 协议定义一个获取支付信息的方法,调用接口是异步操作,所以返回的数据使用block返回

@protocol PayDataPrepareProtocol <NSObject>

@required
- (void)getPayData:(void(^)(id result, NSError *error))block;

@end

微信支付伪代码:

@interface WXPayPrepareData : NSObject <PayDataPrepareProtocol>
@property (nonatomic,strong) NSDictionary *requestParams;

@end

@implementation WXPayPrepareData

- (void)getPayData:(void(^)(id result, NSError *error))block {
    //根据请求参数,使用网络层组件调用API,并返回预支付信息
    block(result,nil);
}

@end

银联支付伪代码:

@interface UnionPayPrepareData : NSObject <PayDataPrepareProtocol>
@property (nonatomic,strong) NSDictionary *requestParams;
@end

@implementation UnionPayPrepareData

- (void)getPayData:(void(^)(id result, NSError *error))block {
    //根据请求参数,使用网络层组件调用API,并返回预支付信息
    block(result,nil);
}
@end

如何能将支付类型与预支付实现类之间建立联系呢?我们需要设计一个配置类来管理这种支付类型与预支付实现类的对应关系 。

支付配置的伪代码:

typedef NS_Enum(NSInteger, PayType) {
    PayTypeForAlipay,    //支付宝支付
    PayTypeForWXPay,    //微信支付
    PayTypeForUPPay,    //银联支付
} 


@interface PayConfig: NSObject

//单例对象
+ (instancetype)config;

//添加获取预支付信息对应的策略类, 没有传递实例对象,避免未使用而造成的内存浪费
- (void)appendPrepayDataStrategy:(Class)strategyClass withPayType:(PayType)payType;

//判断是否存在指定类型对应的实现策略
- (BOOL)containsPrepayDataStrategyWithPayType:(PayType)payType;

//根据支付的枚举类型,获取预支付信息处理对象
- (id<PayDataPrepareProtocol>)getPrepayDataStrategyWithPayType:(PayType)payType;
@end


@interface PayConfig ()
@property (nonatomic,strong) NSMutableDictionary *strategyMap;
@end

@implementation PayConfig

//单例对象
+ (instancetype)config {
    static PayConfig *_instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!_instance) {
           _instance = [[PayConfig alloc] init]; 
        }
    });
    return _instance;
}

//添加获取预支付信息对应的策略类, 没有传递实例对象,避免未使用而造成的内存浪费
- (void)appendPrepayDataStrategy:(Class)strategyClass withPayType:(PayType)payType {
    if (!strategyClass) {
        return;
    }

    //判断是否实现了协议
    if (![strategyClass conformsToProtocol:@protocol(PayDataPrepareProtocol)]) {
        return;
    }
    
    NSString *payTypeKey = [Utils convertPayTypeToString:payType]; //将枚举转成字符串
    [self.strategyMap setObject:strategyClass forKey:payTypeKey];

}

//判断是否存在指定类型对应的实现策略
- (BOOL)containsPrepayDataStrategyWithPayType:(PayType)payType {
    NSString *payTypeKey = [Utils convertPayTypeToString:payType]; //将枚举转成字符串
    return  !self.strategyMap[payTypeKey];
}

//根据支付的枚举类型,获取预支付信息处理对象
- (id<PayDataPrepareProtocol>)getPrepayDataStrategyWithPayType:(PayType)payType {

    if (![self containsPrepayDataStrategyWithPayType:payType]) {
        return nil;
    }

    NSString *payTypeKey = [Utils convertPayTypeToString:payType]; //将枚举转成字符串
    Class cls = self.strategyMap[payTypeKey];

    return [[cls alloc] init]; //在需要时才返回创建的对象
}

//懒加载,需要时创建
- (NSMutableDictionary *)strategyMap {
    if (!_strategyMap) {
        _strategyMap = @{}.mutableCopy;
    }
    return _strategyMap;
}
@end

通过上面的支付配置(单例)对象,我们将以支付类型为key, 以对应的获取预支付信息的类为value, 使用字典来管理。 将配置类设计成单例,这样就可以在支付组件中访问,并使用其中的配置信息。

支付组件的伪代码:

#import "PayConfig.h"

@interface PayManager :NSObject 

//调用预支付信息API接口,用到的请求参数
@property (nonatomic,strong) NSDictionary *requestParams;

//支付第三方类型
@property (nonatomic,assign) PayType payType;

//开始支付
- (void)startPay;
@end


@implementation PayManager 


//开始支付
- (void)startPay {
    
    //1. 根据支付类型,判断支付配置中是否有需要请求服务API的处理类
    if ([[PayConfig config] containsPrepayDataStrategyWithPayType:self.payType]) {
        id strategy = [[PayConfig config] getPrepayDataStrategyWithPayType:self.payType];
        
        //利用KVC向请求API接口的策略类传递请求参数
        [strategy setValue:self.requestParams forKey:@“requestParams”];
        
        //准备好请求数据后,开始调用接口API获取所需要的预支付信息
        [strategy getPayData:^(id result, NSError *error ) {
            //拿到需要的预支付信息后,再调起第三方支付组件
            
        }];
    
    }else {
        // 调起第三方支付组件
    }

}
@end

总结

通过我们的进一步设计,支付组件已完全不依赖于网络组件来完成对预支付信息的获取,而且扩展性更强了。 如果以后有新的支付第三方加入进来,且需要获取预支付信息的, 我们只需要实现PayDataPrepareProtocol 协议, 并将其加入到 PayConfig 中就可以了。 通过少量的修改我们就可以完成扩展,也遵循了“开闭原则( 对扩展开放,对修改关闭)” 。

完整的支付组件代码请前往:RZPayManager
在README.md文件中有该组件的使用详解,如果喜欢,点关注支持一下。

后记

如果本文对你有一点帮助的话,欢迎收藏、点赞,感谢。文中如有不对之处,也欢迎大家在评论区指出,共勉。

标签:end,微信,void,iOS,payType,API,银联,支付,组件
From: https://www.cnblogs.com/reyzhang/p/17498798.html

相关文章

  • iOS开发笔记 - 界面调试神器Reveal
    Reveal是iOS开发工具中的神器之一,它能够在应用程序运行过程中调试应用程序界面。通过Reveal我们可以连接到应用程序,并允许开发者编辑各种用户界面参数,结果会马上在用户界面上呈现。就像Web开发人员用浏览器提供的开发人员工具调试页面一样,Reveal允许开发者在不修改代码、不重新构......
  • 【Android】iOS开发中xconfig和script脚本的使用
    利用Xcode进行开发时需要进行很多buildsetting的设置以便能让项目按照设置的进行编译,同时有时候需要在编译时利用script脚本进行一些设置,本文主要介绍xconfig文件和script脚本在Xcode开发中使用。作者:MambaYongXcode编译在使用xconfig时有几个关于Xcode的概念是需要理解的,这里我进......
  • 添加一段代码,让你的网站在微信QQ提示使用浏览器访问
    <script>//跳转提示if(is_weixn_qq()){;window.location.href='https://c.pc.qq.com/middle.html?pfurl='+window.location.href;}functionis_weixn_qq(){//判断当前是否微信/QQ浏览器varua=navigator.userAgent;varisWeixin=!!/MicroMessenger/i.test......
  • ios生命周期整理
    iosAppstates 应用的五种状态State 描述 Notrunning        应用没有被启动;或者应用正在运行但是途中被系统终止了。 Inactive     应用在前台运行,但是还不能接收事件(当时或许正在执行其他代码);一个应用通常只是很短时间停留在这个状态,很快它将切换到......
  • iOS 应用是如何创建的
    iOSapplifecycle生命周期图 第一步:Main有C相关语言开发经验的朋友都知道,所有程序运行都是从main程序开始的。#import<UIKit/UIKit.h>#import"NoteNavAppDelegate.h"intmain(intargc,char*argv[]){@autoreleasepool{returnUIApplicationMain(arg......
  • Android仿微信图片浏览
    实现原理自定义PopupWindow+RecyclerView+TouchImageViewPopupWindow与AlertDialog的区别最关键的区别是AlertDialog不能指定显示位置,只能默认显示在屏幕最中间(当然也可以通过设置WindowManager参数来改变位置)。而PopupWindow是可以指定显示位置的,十分灵活。要生成一个PopupWindow......
  • vue+axios实现token无感刷新
    原文出处:https://www.jb51.net/javascript/286094r4h.htm 通常,对于一些需要记录用户行为的系统,在进行网络请求的时候都会要求传递一下登录的token。不过,为了接口数据的安全,服务器的token一般不会设置太长,根据需要一般是1-7天的样子,token过期后就需要重新登录。不过,频繁的登录会......
  • 不登录微信,微信的聊天记录加密的图片还能恢复吗
    1-6大家是否有需要在不登录微信的情况下查看微信的图片呢?我是一个网管,和很多人交流后发现不少人都有这个需求。但是微信中收发的图片保存为加密的DAT文件,无法直接查看。因此这里介绍一个小工具,名为《天才小网管DAT转JPG》。它可以在不登录微信的情况下将微信的聊天中收到的加密DAT......
  • 微信小程序 使用输入法的回车搜索
    有这样一个需求 搜索框没有确定键需要用输入法的回车键来进行搜索触发如图这时候只需要在input中使用bindconfirm事件就可以了 这样就可以拿到了......
  • iOS开发笔记 - Objective-C和JavaScript的混编
    最近看了一个对Github上面编程语言使用统计的排行榜,JavaScript真可以说是一枝独秀,很难想象20年前,这个语言只是浏览器中的装饰性语言,能做的事情也就是一点特效或者检查一下要提交给服务器的表单是否满足要求。今天的JavaScript已经是一个全栈语言,从客户端到服务器无所不在。很多编程......