漫談golang設計模式 簡易工廠模式

来源:https://www.cnblogs.com/windWheel/archive/2019/08/31/windWheel.html
-Advertisement-
Play Games

目前學習golang的主要需求是為了看懂TiDB的源碼,下麵我們複習一下簡易工廠模式的思想 工廠類型分為三種,創建型模式,結構型模式,行為型模式。 簡單工廠 使用場景:考慮一個簡單的API設計,一個模塊可以提供不同的APi,這些Api都源自同一個基類,不過在繼承基類後不同的子類修改了部分屬性,從而可 ...


目前學習golang的主要需求是為了看懂TiDB的源碼,下麵我們複習一下簡易工廠模式的思想

工廠類型分為三種,創建型模式,結構型模式,行為型模式。

簡單工廠

使用場景:考慮一個簡單的API設計,一個模塊可以提供不同的APi,這些Api都源自同一個基類,不過在繼承基類後不同的子類修改了部分屬性,從而可以產生不同的功能實現,如果希望在使用這些Api時,只需要知道表示該api的一個參數,並提供一個調用方便的方法,把該參數傳入方法即可返回一個相應的按鈕對象,此時,就可以使用簡單工廠模式。

定義

簡單工廠模式(Simple Factory Pattern):又稱為靜態工廠方法(Static Factory Method)模式,它屬於類創建型模式。在簡單工廠模式中,可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。

組成角色

  • Factory:工廠角色

     工廠角色負責實現創建所有實例的內部邏輯
  • Product:抽象產品角色

     抽象產品角色是所創建的所有對象的父類,負責描述所有實例所共有的公共介面
  • ConcreteProduct:具體產品角色

      具體產品角色是創建目標,所有創建的對象都充當這個角色的某個具體類的實例。

從時序圖來看,我們可以考慮用構造函數在初始化實例的時候進行重載,但是golang並沒有構造函數。所以我們採用介面實現的方式,先構造一個介面類型的方法作為重載方法,根據傳入的值進行決定需要使用哪一個方法。

package designmode

import "fmt"

type API interface {
    Say(name string) string
}

func NewAPI( t int)API  {
    if t ==1{
        return &hiAPI{}
    }else if t == 2 {
        return &helloAPI{}
    }
    return nil
}

type hiAPI struct {
    say string
}

func (*hiAPI) Say(name string) string {
    return fmt.Sprintf("Hi, %s", name)
}


type helloAPI struct {

}
//Say hello to name
func (*helloAPI) Say(name string) string {
    return fmt.Sprintf("Hello, %s", name)
}

為什麼需要使用指針傳遞?

我們做一個簡單的實驗,分別列印變數和記憶體地址

  • 值傳遞
package learn

import "fmt"

type WindWheel struct {
    Age int
    Name string
}

func passV(w WindWheel)  {
    w.Age++
    w.Name = "Greact"+w.Name
    fmt.Printf("傳入修改後的windWheel:\t %+v, \t記憶體地址;%p\n",w,&w)
}

func main()  {
    parrot :=WindWheel{Age: 1,Name: "Blue"}
    fmt.Printf("原始的windWheel:\t\t %+v,  \t\t記憶體地址: %p\n",parrot,&parrot)
    passV(parrot)
    fmt.Printf("調用後原始的windWheel:\t %+v, \t\t記憶體地址: %p\n",parrot,&parrot)


}

列印結果:

原始的windWheel:        {Age:1 Name:Blue},         記憶體地址:0xc420012260
傳入修改後的windWheel:     {Age:2 Name:GreatBlue},    記憶體地址:0xc4200122c0
調用後原始的windWheel:     {Age:1 Name:Blue},         記憶體地址:0xc420012260

引用傳遞

package learn

import "fmt"
type WindWheel struct {
    Age  int
    Name string
}
func passP(w *WindWheel) {
    w.Age++
    w.Name = "Great" + w.Name
    fmt.Printf("傳入修改後的WindWheel:\t %+v, \t記憶體地址:%p, 指針的記憶體地址: %p\n", *w, w, &w)
}
func main() {
    parrot := &WindWheel{Age: 1, Name: "Blue"}
    fmt.Printf("原始的WindWheel:\t\t %+v, \t\t記憶體地址:%p, 指針的記憶體地址: %p\n", *parrot, parrot, &parrot)
    passP(parrot)
    fmt.Printf("調用後原始的WindWheel:\t %+v, \t記憶體地址:%p, 指針的記憶體地址: %p\n", *parrot, parrot, &parrot)
}

列印結果

原始的WindWheel:        {Age:1 Name:Blue},         記憶體地址:0xc420076000, 指針的記憶體地址: 0xc420074000
傳入修改後的WindWheel:     {Age:2 Name:GreatBlue},    記憶體地址:0xc420076000, 指針的記憶體地址: 0xc420074010
調用後原始的WindWheel:     {Age:2 Name:GreatBlue},    記憶體地址:0xc420076000, 指針的記憶體地址: 0xc420074000

這說明golang在使用值傳遞時會為傳入的值創建一個副本存儲,所以該變數的地址會變,如果根據傳入時的工廠模式的值進行取值,是取不到的,由於記憶體地址不同會造成記憶體泄漏。所以應該採取引用傳遞,只會為傳入的指針創建一個副本,並不影響變數的地址更改

此處引用鳥窩前輩的一些總結:

如何選擇 T 和 *T

  • 不想變數被修改。 如果你不想變數被函數和方法所修改,那麼選擇類型T。相反,如果想修改原始的變數,則選擇*T
  • 如果變數是一個大的struct或者數組,則副本的創建相對會影響性能,這個時候考慮使用*T,只創建新的指針,這個區別是巨大的
  • (不針對函數參數,只針對本地變數/本地變數)對於函數作用域內的參數,如果定義成T,Go編譯器儘量將對象分配到棧上,而*T很可能會分配到對象上,這對垃圾回收會有影響

模式分析

將對象的創建和對象本身業務處理分離可以降低系統的耦合度,使得兩者修改起來都相對容易。

簡單工廠模式最大的問題在於工廠類的職責相對過重,增加新的產品需要修改工廠類的判斷邏輯,這一點與開閉原則是相違背的。
簡單工廠模式的要點在於:當你需要什麼,只需要傳入一個正確的參數,就可以獲取你所需要的對象。

簡單工廠模式的優點

工廠類含有必要的判斷邏輯,可以決定在什麼時候創建哪一個產品類的實例,客戶端可以免除直接創建產品對象的責任,而僅僅“消費”產品;簡單工廠模式通過這種做法實現了對責任的分割,它提供了專門的工廠類用於創建對象。
客戶端無須知道所創建的具體產品類的類名,只需要知道具體產品類所對應的參數即可,對於一些複雜的類名,通過簡單工廠模式可以減少使用者的記憶量。
通過引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性。

簡單工廠模式的缺點

由於工廠類集中了所有產品創建邏輯,一旦不能正常工作,整個系統都要受到影響。
使用簡單工廠模式將會增加系統中類的個數,在一定程式上增加了系統的複雜度和理解難度。
系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能造成工廠邏輯過於複雜,不利於系統的擴展和維護。
簡單工廠模式由於使用了靜態工廠方法,造成工廠角色無法形成基於繼承的等級結構。

適用環境

在以下情況下可以使用簡單工廠模式:

工廠類負責創建的對象比較少:由於創建的對象較少,不會造成工廠方法中的業務邏輯太過複雜。
客戶端只知道傳入工廠類的參數,對於如何創建對象不關心:客戶端既不需要關心創建細節,甚至連類名都不需要記住,只需要知道類型所對應的參數。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 08.31自我總結 Vue CLI項目 axios前後端交互 一.模塊的安裝 二.配置main.js 三.使用 JS created() { // 組件創建成功的鉤子函數 // 拿到要訪問課程詳情的課程id let id = this.$route.params.pk || this.$route. ...
  • Vue CLI項目中路由傳參 一.標簽傳參方式:\\ 第一種 router.js 傳遞層 接收層 演變體 第二種 router.js 傳遞層 接收層 第三種 router.js 傳遞層 接收層 二.邏輯傳參:this.$router 第一種 python """ 路由: path: '/course ...
  • 1、Uncaught SyntaxError: Unexpected end of input js報錯: 翻譯:語法錯誤:輸入意外終止 原因:頁面代碼寫的不規範 ╮(╯▽╰)╭ 其中的某條語句,沒有正常結束 ε=(´ο`*))) 所以這個時候就要好好檢查自己寫的代碼有沒有什麼符號忘加啦,或者是雙引 ...
  • 讓多個組件使用同一個掛載點,並動態切換,這就是動態組件。 通過使用保留的 <component>元素,動態地綁定到它的 is 特性,可以實現動態組件。 方式一:局部註冊所需組件 使用<keep-alive>緩存 <keep-alive> 包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。和 < ...
  • 前言 最近在公司寫一個混合 app 項目,頁面基本全部都是用 H5 完成,嵌入到原生 webview 下。發現一個問題,在 iPhone 6 下 蘋果手機的狀態欄會擋住頁面,導致頁面下移,樣式錯亂,最後網上查找了些解決辦法,加了一條 meta 標簽解決了問題。今天特來總結下常用的移動端開發需要註意的 ...
  • 正則表達式是構成搜索模式的字元序列。該搜索模式可用於文本搜索和文本替換操作。簡單來說,正則表達式其實是一種規則,主要應用在檢測字元串是否符合我們定義的規則上。 一 創建正則表達式 創建正則表達式有兩種方式,他們都返回一個正則表達式對象(RegExpObject): 1, 字面量方式 2, 構造函數方 ...
  • 嘗試模仿京東的“發現好貨”模塊的可用滑塊滑動的緩動圖 <! more JS代碼 HTML代碼 CSS代碼 ...
  • HTML表單: HTML表單用於搜集不同類型的輸入 標簽元素: HTML表單用於收集用戶輸入; form元素定義HTML表單 屬性列表: | 屬性 | 描述 | | | | | accept charset | 規定在被提交表單中使用的字元集(預設:頁面字元集)。 | | action | 規定向何 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...