客戶決策 | Go語言設計模式實戰

嗯,個人代碼沒有 else系列,一個設計模式業務真實使用的golang系列。

個人代碼沒有else系列.jpg

前言

本系列主要分享,如何在咱們的真實業務場景中使用設計模式。git

本系列文章主要採用以下結構:github

  • 什麼是「XX設計模式」?
  • 什麼真實業務場景可使用「XX設計模式」?
  • 怎麼用「XX設計模式」?

本文主要介紹「策略模式」如何在真實業務場景中使用。golang

什麼是「策略模式」?

「策略模式」比較簡單,你們日常工做中應該常常使用到,因此本文做爲複習,幫助你們溫故知新。咱們先來看下定義:算法

不一樣的算法按照統一的標準封裝,客戶端根據不一樣的場景,決策使用何種算法。

上面的概念的關鍵詞:sql

  • 算法:就是行爲
  • 標準:就是interface
  • 客戶端:客戶端是相對的,誰調用誰就是客戶端
  • 場景:判斷條件
  • 決策:判斷的過程

概念很容易理解,很少說。json

「策略模式」的優點:segmentfault

  • 典型的高內聚:算法和算法之間徹底獨立、互不干擾
  • 典型的鬆耦合:客戶端依賴的是接口的抽象方法
  • 沉澱:每個封裝好的算法都是這個技術團隊的財富,且將來能夠被輕易的修改、複用

什麼真實業務場景能夠用「策略模式」?

每一行代碼下面的十字路口

當代碼的下一步面臨選擇的時候均可以使用「策略模式」,咱們把不一樣選擇的算法按照統一的標準封裝,獲得一類算法集的過程,就是實現「策略模式」的過程。設計模式

咱們有哪些真實業務場景能夠用「策略模式」呢?

好比:緩存

  • 緩存: 使用什麼樣的nosql
  • 存儲: 使用什麼樣的DB
  • 支付: 使用什麼樣的支付方式
  • 等等...

本文以支付接口舉例,說明「策略模式」的具體使用。微信

怎麼用「策略模式」?

關於怎麼用,徹底能夠生搬硬套我總結的使用設計模式的四個步驟:

  • 業務梳理
  • 業務流程圖
  • 代碼建模
  • 代碼demo

業務梳理

咱們以某團的訂單支付頁面爲例,頁面上的每個支付選項都是一個支付策略。以下:

用戶可使用:

  • 美團支付(策略)
  • 微信支付(策略)
  • 支付寶支付(策略)

用戶決定使用美團支付下的銀行卡支付方式的參數

用戶決定使用支付寶網頁版支付方式的參數

注:不必定徹底準確。

業務流程圖

咱們經過梳理的文本業務流程獲得了以下的業務流程圖:

注:流程不必定徹底準確。

代碼建模

「策略模式」的核心是接口:

  • PaymentInterface

    • Pay(ctx *Context) error 當前支付方式的支付邏輯
    • Refund(ctx *Context) error 當前支付方式的退款邏輯

僞代碼以下:

// 定義一個支付接口
- `PaymentInterface`
    + 抽象方法`Pay(ctx *Context) error`: 當前支付方式的支付邏輯
    + 抽象方法`Refund(ctx *Context) error`: 當前支付方式的退款邏輯

// 定義具體的支付方式 實現接口`PaymentInterface`

- 具體的微信支付方式`WechatPay`
    +  實現方法`Pay`: 支付邏輯
    +  實現方法`Refund`: 支付邏輯
- 具體的支付寶支付網頁版方式`AliPayWap`
    +  實現方法`Pay`: 支付邏輯
    +  實現方法`Refund`: 支付邏輯
- 具體的支付寶支付網頁版方式`BankPay`
    +  實現方法`Pay`: 支付邏輯
    +  實現方法`Refund`: 支付邏輯

// 客戶端代碼
經過接口參數pay_type的值判斷是哪一種支付方式策略

同時獲得了咱們的UML圖:

代碼demo

package main

import (
    "fmt"
    "runtime"
)

//------------------------------------------------------------
//個人代碼沒有`else`系列
//策略模式
//@auhtor TIGERB<https://github.com/TIGERB>
//------------------------------------------------------------

const (
    // ConstWechatPay 微信支付
    ConstWechatPay = "wechat_pay"
    // ConstAliPayWap 支付寶支付 網頁版
    ConstAliPayWap = "AliPayWapwap"
    // ConstBankPay 銀行卡支付
    ConstBankPay = "quickbank"
)

// Context 上下文
type Context struct {
    // 用戶選擇的支付方式
    PayType string `json:"pay_type"`
}

// PaymentInterface 支付方式接口
type PaymentInterface interface {
    Pay(ctx *Context) error    // 支付
    Refund(ctx *Context) error // 退款
}

// WechatPay 微信支付
type WechatPay struct {
}

// Pay 當前支付方式的支付邏輯
func (p *WechatPay) Pay(ctx *Context) (err error) {
    // 當前策略的業務邏輯寫這
    fmt.Println(runFuncName(), "使用微信支付...")
    return
}

// Refund 當前支付方式的支付邏輯
func (p *WechatPay) Refund(ctx *Context) (err error) {
    // 當前策略的業務邏輯寫這
    fmt.Println(runFuncName(), "使用微信退款...")
    return
}

// AliPayWap 支付寶網頁版
type AliPayWap struct {
}

// Pay 當前支付方式的支付邏輯
func (p *AliPayWap) Pay(ctx *Context) (err error) {
    // 當前策略的業務邏輯寫這
    fmt.Println(runFuncName(), "使用支付寶網頁版支付...")
    return
}

// Refund 當前支付方式的支付邏輯
func (p *AliPayWap) Refund(ctx *Context) (err error) {
    // 當前策略的業務邏輯寫這
    fmt.Println(runFuncName(), "使用支付寶網頁版退款...")
    return
}

// BankPay 銀行卡支付
type BankPay struct {
}

// Pay 當前支付方式的支付邏輯
func (p *BankPay) Pay(ctx *Context) (err error) {
    // 當前策略的業務邏輯寫這
    fmt.Println(runFuncName(), "使用銀行卡支付...")
    return
}

// Refund 當前支付方式的支付邏輯
func (p *BankPay) Refund(ctx *Context) (err error) {
    // 當前策略的業務邏輯寫這
    fmt.Println(runFuncName(), "使用銀行卡退款...")
    return
}

// 獲取正在運行的函數名
func runFuncName() string {
    pc := make([]uintptr, 1)
    runtime.Callers(2, pc)
    f := runtime.FuncForPC(pc[0])
    return f.Name()
}

func main() {
    // 相對於被調用的支付策略 這裏就是支付策略的客戶端

    // 業務上下文
    ctx := &Context{
        PayType: "wechat_pay",
    }

    // 獲取支付方式
    var instance PaymentInterface
    switch ctx.PayType {
    case ConstWechatPay:
        instance = &WechatPay{}
    case ConstAliPayWap:
        instance = &AliPayWap{}
    case ConstBankPay:
        instance = &BankPay{}
    default:
        panic("無效的支付方式")
    }

    // 支付
    instance.Pay(ctx)
}

代碼運行結果:

[Running] go run "../easy-tips/go/src/patterns/strategy/strategy.go"
main.(*WechatPay).Pay 使用微信支付...

結語

最後總結下,「策略模式」抽象過程的核心是:

每一行代碼下面的十字路口

  • 聲明標準:定義interface
  • 封裝算法:按照標準interface封裝分支代碼,獲得每個具體策略
  • 構建算法集:每個具體策略構成策略池子 -> 這就是沉澱的過程
特別說明:
1. 個人代碼沒有`else`,只是一個在代碼合理設計的狀況下天然而然無限接近或者達到的結果,並非一個硬性的目標,務必較真。
2. 本系列的一些設計模式的概念可能和原概念存在差別,由於會結合實際使用,取其精華,適當改變,靈活使用。

文章列表

個人代碼沒有else系列 更多文章 點擊此處查看

3911642037-d2bb08d8702e7c91_articlex.jpg

相關文章
相關標籤/搜索