最近半年在做区块链钱包App的iOS端的开发。
区块链app开发,印象最明显的地方就是,区块链由于币种非常多,不同币种数据结构和处理方法又不完全一样,而每个币种的界面又几乎是一样的。
所以我习惯性地在各种控制器中,用大量if else去判断币种类型,然后分开去处理不同的业务逻辑。
如下面:
页面A为某个币种的交易列表页,关键地方伪代码如下:
if(币种==ETH){
ETH接取交易列表
}else if (币种 == ETH Token){
ETH Token接取交易列表
}else{
常规拉取交易列表
}
而在其它页面如交易发送页B,交易详情确认页C中也出现了大量上面这样的if else写法。
我们的app叫IFWallet(国外商店下载),其中几个页面如下:
资产页
交易记录页
发送页
直到有一天,我想我要做出改变,用我知道的设计模式去重构代码。
首先我想到的是,将if else中的每一种处理逻辑,用block来封装,然后由一个统一的方法输入币种返回处理的block。
伪代码如下:
- (block)fetchBusinessBlockForCoin:(币种){
if(币种==ETH){
return ETH-Block;
}else if (币种 == ETH Token){
return ETH-Token-Block;
}
return 常规-Block;
}
但后面我想,这种方法只是抽出了逻辑到另一个地方而已。
我想,以前的代码最大问题在于,各个页面都有大量的if else, 势必难以维护和拓展。如果增加一种币种,就要去四五个页面改if else代码。容易漏掉,也难阅读。
于是,我想到了,能不能在一个地方一次性地指定不同币种由什么样的逻辑去处理?
因此,我想到了,将一个币种的所有业务封装成一个对象CB,伪代码如下:
class 币种业务类CB {
(成员变量:)
交易记录拉取类HF对象;
交易构建类DC对象;
交易发送类DS对象;
}
这样,不同币种的不同业务可以去继承HF,DC,DS类,等于是用组合模式,把不同的业务的处理对象,组合成一个整体的币种处理对象。
然后,我们再用工厂方法模式,去为不同的币种创建对应的币种业务类CB对象。伪代码如下:
class 币种业务类工厂类CB factory{
+ (币种业务类CB对象)buildCBWithCoin:(币种){
币种业务类CB对象 cb
if(币种==ETH){
cb. 交易记录拉取类HF对象 = ETH 交易记录拉取类HF对象;
cb.交易构建类DC对象 = ETH交易构建类DC对象;
cb.交易发送类DS对象 = ETH交易发送类DS对象;
}else if (币种 == ETH Token){
cb. 交易记录拉取类HF对象 = ETH Token交易记录拉取类HF对象;
cb.交易构建类DC对象 = ETH Token交易构建类DC对象;
cb.交易发送类DS对象 = ETH Token交易发送类DS对象;
}else{
cb. 交易记录拉取类HF对象 = 常规交易记录拉取类HF对象;
cb.交易构建类DC对象 = 常规交易构建类DC对象;
cb.交易发送类DS对象 = 常规交易发送类DS对象;
}
return cb;
}
}
也就是说,币种的某一业务,会因币种不同而不一样,不同的实现只需继承自同一个父类即可,如“ETH 交易记录拉取类HF”和 “常规交易记录拉取类HF”,“常规交易构建类DC” 都 继承自 交易记录拉取类HF;
然后在不同的几个页面,就可以直接调用父类的方法,就会根据多态,而去决定用哪个子类的具体实现去处理这个币种的业务。
因此,在我们拿到币种时,就配好了相应的业务处理方法,只需一次性用if else配置好,后面就再也不用写if else了,代码简洁,同时,改动或增加币种时,只城增加业务类,和修改工厂类就行了,不用去各个页面改动。维护成本,大大降低。
我个人认为,很多时候我们写代码使用面向对象思想仅停留在了“使用对象"的层面上,而没用将"业务和逻辑"也应用面向对象思想。
设计模式真是个好东西,请善待它。
唐京
2019/04/11