如何用 Go 寫出優美的代碼 - Go 的設計模式【簡單工廠模式,抽象工廠模式】篇二

大家好,我是追麾 (hui)。

上一次分析完 Go 的設計模式第一篇,有同學後臺問一些設計原則的問題,這篇我們就來講一下設計的一些原則,然後再繼續設計模式的學習。下圖是本文提綱。

關於程序設計有六大原則,具體原則如下,當然這個不是 Go 語言獨有的,而是所有的語言都有的。瞭解了每個程序設計原則的目的,並且運用到我們的程序中去,會讓我們的代碼可讀性高,更加優美,你也會更加愛上寫代碼。

單一職責原則

定義:一個類或者一個模塊只承擔一個業務職責,一般地,一個類或者模塊內部儘量做到高內聚,不同的類或者模塊之間做到低耦合,這樣的話代碼質量就會很高。在 Go 語言裏面一個 struct 就算一個對象,如果這個對象加上一些方法就能算一個類。

主要目的:單一職責的原則是讓類或者模塊的職責更加清晰明確,另外能降低程序複雜度,提高程序可讀性和可維護性,也從一定程度下說可能可擴展性要好一些。

開放封閉原則

定義:一個(類、模塊、函數等等)可以擴展,但是不可修改。在 Go 語言裏面是沒有辦法直接通過繼承重寫的方式實現擴展,但是可以通過組合的方式來實現繼承並擴展,後面我們會講到組合模式會涉及到這個開放封閉原則。

主要目的:開放封閉原則主要是在軟件需求發生變化時,目標類和模塊的代碼可以通過代碼擴展實現新的需求,而不是修改已有的類或者模塊,主要是防止在已有代碼邏輯上修改製造代碼缺陷。

里氏替換原則

定義:子類對象必須能夠完全替換掉它們的父類對象,而不需要改變父類的任何屬性。在 Go 裏面可以通過接口的多重組合來實現繼承和多態,但是實現起來是相對比較複雜的。

主要目的:里氏替換原則的核心目的主要是爲了實現多態,通過繼承的方式重寫父類的方法,這樣父類定義的對象引用可以通過不同的子類進行調用,然而同一個調用就能表現多態特徵。

依賴倒置原則

定義:高層模塊不應依賴於低層模塊,二者都應該依賴於抽象(抽象類和接口);抽象(抽象類和接口)不應依賴於細節,細節應依賴於抽象(抽象類和接口)。在 Go 語言中這個原則也是保留的,但是 Go 只有接口,是沒有抽象類。

主要目的:依賴倒置原則主要是解耦的目的,減少類間的耦合性,能提高系統的穩定性,降低並行開發引起的風險,提高代碼的可讀性和可維護性。

接口分離原則

定義:建立單一接口,不要建立臃腫龐大的接口。再通俗一點講:接口儘量細化,同時接口中的方法儘量少。在 Go 語言中接口分離原則原則制定和其他語言沒有差異,接口分離原則主要還是由開發者來決定的。

主要目的:接口分離原則主要是爲了讓接口儘量少,代碼抽象度高,可複用性高。在根據接口隔離原則拆分接口時,是必須要滿足單一職責原則。

迪米特原則(Least Knowledge Principle)

定義:其實就是知道最少原則,也就是調用涉及的依賴儘可能的小。在 Go 語言中主要是通過大寫方法名來實現讓包外進行訪問,這樣在 Go 語言中實現迪米特原則也就比較方便了。

主要目的:迪米特原則是降低類間耦合,讓類之間弱耦合,只有弱耦合了以後,類的複用率纔可以提高,也可以說這個原則是讓類之間達到解耦目的。

到這裏我算是回答了後臺諮詢我的同學了,關於設計原則我只分享了定義以及每個設計原則的核心目的是什麼,後面分享剩餘的設計模式之後也會涉及到這些原則,並且運用到實際的模式中去。比如說第一篇的單例模式,其主要設計的原則是單一職責原則。第一篇工廠方法模式其主要設計的原則參照依賴倒置原則和開放封閉原則。

Go 的簡單工廠模式

業界簡單工廠模式定義:將目標產品創建行爲分配給工廠類,由工廠類向客戶端提供產品對象創建服務。

簡單工廠模式優缺點

簡單工廠模式的應用場景

簡單工廠模式實現方式

像簡單工廠模式其主要可以參照迪米特原則,讓實現的方法或者類對外輸出被創建與初始化。

我們的工作中經常會對接多個支付平臺,然後需要去調用支付平臺進行下單,每個支付平臺就是不同的對象,我們通過一個 NewPayPlatform 創建對象,返回接口。這樣就實現了簡單工廠模式。下面我們通過業務中 Go 語言代碼具體來講解簡單工廠模式。

package main

import "fmt"

func main() {
 NewPayPlatform("test").CreatePayOrder()
}

// 支付平臺的公共接口
type PayPlatformInterface interface {
 //創建支付訂單
 CreatePayOrder()
}

type AliPay struct {
}

func (a *AliPay) CreatePayOrder() {
 fmt.Println("CreatePayOrder 支付寶")
}

type WeiXinPay struct {
}

func (a *WeiXinPay) CreatePayOrder() {
 fmt.Println("CreatePayOrder 微信支付")
}

// 簡單工廠模式,AliPay 和 WeiXinPay是不同的對象, PayPlatformInterface 是接口
func NewPayPlatform(platform string) PayPlatformInterface {
 switch platform {
 case "alipay":
  return &AliPay{}
 case "weixin":
  return &WeiXinPay{}
 }
 // 默認是調用支付寶
 return &AliPay{}
}

看完 Go 的簡單工廠模式,是不是發現和之前的工廠方法模式很像?工廠方法模式的調用可以不用組裝公共方法,兩種側重點不一樣的,工廠方法模式是側重定義一批方法,簡單工廠模式是側重調用。

Go 的抽象工廠模式

業界抽象工廠模式定義:爲創建一組相關或者相互依賴的對象提供一個接口,而無需指定它們的具體類。抽象工廠模式可以說是是工廠方法模式的升級版,當需要創建的產品有多個產品線(產品族)時使用抽象工廠模式是比較好的選擇。

抽象工廠模式優缺點

抽象工廠模式的應用場景:當需要創建的對象是一系列相互關聯或相互依賴的產品族時,便可以使用抽象工廠模式,主要是讓產品簇實現軟件的可配置性。

抽象工廠模式實現方式

在 Go 的設計模式第一篇工廠方法模式裏面我們講了不同廠商的調用,把公共的方法封裝成一批方法組,我們還是上一次的例子做一下升級來講解一下抽象工廠模式。

我們在做聚合廣告需要拉取 facebook 的數據,facebook 當成一個工廠,facebook 是 auth 1.0 授權是這個工廠方法,頭條當成一個工廠,頭條 auth 2.0 授權是這個工廠的方法。我們再建一個接口組合兩個工廠的方法。下面我們具體看下 Go 的示例如何實現抽象工廠。

package main

import "fmt"

func main() {
 a := AuthFactory{}
 a.produceAuth1("fb").auth1()
}

type Auth1 interface {
 auth1()
}

// facebook 用auth1授權
type FaceBookAuth struct {
}

func (f *FaceBookAuth) auth1() {
 fmt.Println("facebook auth1")
}

type Auth2 interface {
 auth2()
}

// toutiao 用auth2授權
type TouTiaoAuth struct {
}

func (t *TouTiaoAuth) auth2() {
 fmt.Println("toutiao auth2")
}

// 抽象公共調用
type AbstractFactory interface {
 produceAuth1(firm string) Auth1
 produceAuth2(firm string) Auth2
}

type AuthFactory struct {
}

func (a *AuthFactory) produceAuth1(firm string) Auth1 {
 switch firm {
 case "fb":
  return &FaceBookAuth{}
 }
 return nil
}

func (a *AuthFactory) produceAuth2(firm string) Auth2 {
 switch firm {
 case "toutiao":
  return &TouTiaoAuth{}
 }
 return nil
}

分享完工廠模式(對工廠方法模式不瞭解的可以查看上一篇文章:【建議收藏】如何用 Go 寫出優美的代碼 - Go 的設計模式【單例模式,工廠方法模式】篇一),簡單工廠模式,抽象工廠模式,我們這裏做一下總結。

最後

如果這篇文章對您有所幫助,或者有所啓發的話,求一鍵三連:點贊、轉發、在看,您的支持是我堅持寫作最大的動力。歡迎大家掃碼進羣一起學習交流。

利志分享 分享技術,職場,人生感悟等,專注架構,go,k8s,kafka,clickhouse,個人小站:bbs.zengzhihai.com

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/89k_-JHxYsU4RGE5sRTfbQ