從點外賣選擇不同支付方式型別考慮對應的設計模式
日記:2020/12/19天氣晴,有陽光的真是太棒了,這麼好的天氣,午餐適合點外賣。糾結了一家一家商店後我終於點了一份外賣,併發起了支付。
這時候支付方式 彈出了n種選擇:
作為一個後端開發,此刻我的想法便是,莫非各大行業領頭羊中的開發大佬會不會和我這個菜雞一樣每選擇一個支付方式,就是給出一個對應的後端介面
於是有了下面的設計方案:
美團支付->呼叫介面A 如/pay/meituan
微信支付->呼叫介面B /pay/weixin
支付寶支付->呼叫介面C/pay/zhifubao
你來啥就給你做啥。
一、暴力無設計模式法
以簡單的支付寶和微信支付介面為例
interface PayMode{ void pay(); } class WeiXinPay implements PayMode { @Override public void pay() { } } class AliPay implements PayMode { @Override public void pay() { } } //支付寶支付 假定給app的請求介面 指定url XXX getPay() { new AliPay().pay(); } // 微信支付 假定給app的請求介面 XXX getPay() { new WeiXinPay().pay(); }
你來幾個方式,我就給你new一個對應的支付方式,我就給你一個介面,重新整。
優點:
我給你支付方式介面是新增的,不可能影響到以前的介面,新支付出了bug可以快速定位,以前的接口出bug不關我的事,你抓週樹人關我(沃德天魏社麼這莫帥)什麼事。
缺點 :
加個新的支付方式,我就的給你加一個新的請求,介面,就需要後端重複一系列邏輯比較麻煩。
二 工廠模式
既然都是打工人,那麼打工人之間何必為難打工人呢,你這個介面打工人直接找自己的工廠(領隊)分配給你一個支付方式的打工人了,為什麼你要一直約束我這個打工人的一切,連我的出生new都約束了太痛苦了。
根據上面各個介面都是自己new一個例項,然後進行搞事情。那麼這塊業務其實可以交給領導人來執行也就是工廠模式,那麼 這是出現一個工廠:
class PayFactory {
PayMode getPayMode(String mode) {
if ("支付寶支付".equals(mode)) {
return new AliPay();
} else if ("微信支付".equals(mode)) {
return new WeiXinPay();
}
return null;
}
}
//支付寶支付 假定給app的請求介面
指定url
XXX getPay() {
new payFactory.getPayMode("支付寶").pay();
}
// 微信支付 假定給app的請求介面
XXX getPay() {
new payFactory.getPayMode("微信").pay();
}
// 進一步融合為一個介面
class PayParam {
String mode;
double money;
。。。
}
// 假定給app的支付請求請求介面
XXX getPay(PayParam payParam) {
PayFactory.getPayMode(payParam.getMode()).pay();
}
根據你的需求,我可以聽你的要做啥,畢竟為了工錢,但是你不能控制我的生命。
優點:
減少了介面程式碼,解決了介面的選擇問題
缺點:
每多一個支付方式,我就要在工廠裡面加,if else越來越多,改動可能會影響到已有的介面,同時如果需要對這個例項before和after做些啥,又得寫一堆程式碼
特點:工廠模式只負責了,給你一個例項,具體做啥,還是要你根據這個例項自己呼叫對應的方法。
三 策略模式
特點:直接通過指定的策略來獲取執行結果。
class PayStrategy {
private PayMode payMode;
public PayStrategy(PayMode payMode) {
this.payMode = payMode;
}
public void pay() {
do sth();
payMode.pay();
do sth();
}
}
// 假定給app的支付請求請求介面
XXX getPay(PayParam payParam) {
PayStrategy payStrategy = new PayStrategy(payParam.getMode());
payStrategy.pay();
}
優點:通過指定策略可以做一些before() 和After()的事情。工廠模式能做的我都能更簡單的實現。
缺點:指定策略的模型不能隨意改動,需要極度抽象化。
四 抽象工廠
字面意思就是將工廠也抽象化,先通過抽象工廠生成一個具體的例項工廠,在通過該例項工廠獲取到對應的產品。
(將多個不同產品的工廠,實現抽象為新工廠的產品族,如衣服和褲子兩個不同產品的工廠,抽象為一個套裝的新工廠(程式碼案例為支付和退款兩個產品,抽象為一個交易工廠))
假設此時我們有需要一個退款的業務,假設我根據退款有生成了一個對應的產品邏輯(實際上支付和退款完全可以呼叫一個PayMode中的實現邏輯,即處理支付也處理退款)
interface RefundMode{
void refund();
}
class WeiXinRefund implements RefundMode {
@Override
public void refund() {
}
}
class AliRefund implements RefundMode {
@Override
public void refund() {
}
}
此時若使用 工廠模式,則需要再次建立一個工廠
class RefundFactory {
RefundMode getRefundMode(String mode) {
if ("支付寶支付".equals(mode)) {
return new AliRefund();
} else if ("微信支付".equals(mode)) {
return new WeiXinRefund();
}
return null;
}
}
這時候我們可以將這兩個工廠抽象化為交易工廠:
abstract class AbstractFactory {
abstract PayMode getPayMode(String mode);
abstract RefundMode getRefundMode(String mode);
}
那麼對應兩個工廠分別為:
class PayFactory extends AbstractFactory{
PayMode getPayMode(String mode) {
if ("支付寶支付".equals(mode)) {
return new AliPay();
} else if ("微信支付".equals(mode)) {
return new WeiXinPay();
}
return null;
}
@Override
RefundMode getRefundMode(String mode) {
return null;
}
}
class RefundFactory extends AbstractFactory{
@Override
PayMode getPayMode(String mode) {
return null;
}
RefundMode getRefundMode(String mode) {
if ("支付寶支付".equals(mode)) {
return new AliRefund();
} else if ("微信支付".equals(mode)) {
return new WeiXinRefund();
}
return null;
}
}
// 在建立一個用於生成對應抽象工廠的工具類
class FactoryUtil {
static AbstractFactory getFactory(String factoryMode) {
if ("支付".equals(factoryMode)) {
return new PayFactory();
} else if ("退款".equals(factoryMode)) {
return new RefundFactory();
}
return null;
}
}
// 具體呼叫則:
FactoryUtil.getFactory("支付").getPayMode("支付寶").pay();
五 總結
抽象工廠就是在工廠模式的基礎上將對應的工廠通過實現介面或抽象介面化,能得到對應的具體工廠,然後再通過對應工廠得到具體的實體類物件。
工廠模式注重的是獲取到對應的例項物件(再通過例項物件進行具體做什麼),而策略模式注重於該具體做什麼。
模板方法就簡單描述下,通過抽象類實現介面,將重複的程式碼再抽象類中實現,而具體類則是繼承對應的抽象類,只需要修改對應具體類特殊處理的步驟。