設計模式:程序員跳不開的坑

學編程,老是逃不了要學「算法」,也總跳不開要學「設計模式」。程序員

不管學習什麼語言,設計模式始終是咱們必須掌握的,這是程序員的基本功。算法

設計模式(Design pattern)是一套被反覆使用、多數人知曉的、通過分類編目的、代碼設計經驗的總結。編程

使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 毫無疑問,設計模式於己於他人於系統都是多贏的,設計模式使代碼編制真正工程化,設計模式是軟件工程的基石,如同大廈的一塊塊磚石同樣。設計模式

項目中合理的運用設計模式能夠完美的解決不少問題,每種模式在如今中都有相應的原理來與之對應,每個模式描述了一個在咱們周圍不斷重複發生的問題,以及該問題的核心解決方案,這也是它能被普遍應用的緣由。app

今天給你們推薦的新課《Go 語言實現 23 種設計模式》,教程涉及7大設計原則、23種設計模式,每種設計模式都從定義、應用及Golang實例三個部分進行詳細介紹。函數

本課須要學員對 Go 語言有必定的基礎哦,可先學習《Go 語言簡明教程》以後再來學習本課。學習

本課程概念較多,受篇幅限制,不宜放過多文字,下面截取課程第一章內容給你們介紹第1種設計原則——開閉原則的概念,想要學習完整設計原則及設計模式的小夥伴請移步至《Go 語言實現 23 種設計模式》學習整個課程測試

開閉原則

開閉原則(Open Closed Principle,OCP) 由勃蘭特.梅耶(Bertrand Meyer)提出,他在 1988 年的著做《面向對象軟件構造》( Object Oriented Software Construction)中提出:軟件實體應當對擴展開放,對修改關閉(Software entities should be open for extension, but closed for modification),這就是開閉原則的經典定義。命令行

開閉原則是設計模式中的總原則,開閉原則就是說:對拓展開放、對修改關閉。模塊應該在儘量不修改代碼的前提下進行拓展,這就須要使用接口和抽象類來實現預期效果。咱們舉例說明什麼是開閉原則,以 4s 店銷售汽車爲例,其類圖如圖所示:設計

ICar 接口定義了汽車的兩個屬性:名稱和價格。BenzCar 是一個奔馳車的實現類,表明奔馳車的總稱。Shop4S 表明售賣的 4S 店,ICar 接口的代碼清單以下:

<pre> package main
 import "fmt"
 type ICar interface {
 // 車名
 GetName() string
 // 價格
 GetPrice() int
 }
 copy</pre>

通常狀況下 4S 店只出售一種品牌的車,這裏用奔馳爲例,代碼清單以下

<pre> type BenzCar struct {
    name string
    price int
 }
 func (b BenzCar) GetName() string {
    return b.name
 }
 func (b BenzCar) GetPrice() int {
    return b.price
 }
 copy</pre>

這裏咱們模擬一下 4s 店售車記錄:

<pre> func main() {
    var (
        list []ICar
    )
    list = []ICar{}
    list = append(list,&BenzCar{"邁巴赫",130})
    list = append(list,&BenzCar{"AMG",343})
    list = append(list,&BenzCar{"V",60})
    for _,v := range list {
        fmt.Println("車名:",v.GetName(),"\t價格:",v.GetPrice())
    }
 }
 copy</pre>

接下來,咱們在命令行中輸入 cd Principle 先切換到 go 文件所在目錄下,而後執行 go run 1.go 來看咱們的執行結果。以下圖所示:

暫時來看,以上設計是沒有啥問題的。可是,某一天,4s 店老闆說奔馳轎車統一要收取一筆金融服務費,收取規則是價格在 100 萬元以上的收取 5%,50~100 萬元的收取 2%,其他不收取。爲了應對這種需求變化,以前的設計又該如何呢?

目前,解決方案大體有以下三種:

  1. 修改 ICar 接口:在 ICar 接口上加一個 getPriceWithFinance 接口,專門獲取加上金融服務費後的價格信息。這樣的後果是,實現類 BenzCar 也要修改,業務類 Shop4S 也要作相應調整。ICar 接口通常應該是足夠穩定的,不該頻繁修改,不然就失去了接口鍥約性了。
  2. 修改 BenzCar 實現類:直接修改 BenzCar 類的 getPrice 方法,添加金融服務費的處理。這樣的一個直接後果就是,以前依賴 getPrice 的業務模塊的業務邏輯就發生了改變了,price 也不是以前的 price 了。
  3. 使用子類拓展來實現:增長子類 FinanceBenzCar,覆寫父類 BenzCar 的 getPrice 方法,實現金融服務費相關邏輯處理。這樣的好處是:只須要調整 Shop4S 中的靜態模塊區中的代碼,main 中的邏輯是不用作很大的修改的。

新增的 FinanceBenzCar 類代碼清單以下:

<pre> type FinanceBenzCar struct {
    BenzCar
 }
 func (b FinanceBenzCar) GetPrice() int {
    // 獲取原價
    selfPrice := b.price
    var finance int
    if selfPrice >= 100 {
        finance = selfPrice + selfPrice5/100    } else if selfPrice >= 50 {        finance = selfPrice + selfPrice2/100
    } else {
        finance = selfPrice
    }
    return finance
 }
 copy</pre>

主函數:

<pre> func main() {
    var (
        list []ICar
    )
    list = []ICar{}
    list = append(list,&FinanceBenzCar{BenzCar{"邁巴赫",99}})
    list = append(list,&FinanceBenzCar{BenzCar{"AMG",200}})
    list = append(list,&FinanceBenzCar{BenzCar{"V",40}})
    for _,v := range list {
        fmt.Println("車名:",v.GetName(),"\t價格:",v.GetPrice())
    }
 }
 copy</pre>

測試結果

<pre> === RUN   TestBenzCar_GetName
 車名: 邁巴赫     價格: 100
 車名: AMG     價格: 210
 車名: V     價格: 40
 --- PASS: TestBenzCar_GetName (0.00s)
 PASS
 copy</pre>

這樣,在業務規則發生改變的狀況下,咱們經過拓展子類及修改持久層(高層次模塊)便足以應對多變的需求。開閉原則要求咱們儘量經過拓展來實現變化,儘量少地改變已有模塊,特別是底層模塊。

開閉原則總結:

  • 提升代碼複用性
  • 提升代碼的可維護性

本課不像其餘項目實戰課程那般,相對晦澀難懂,不那麼富有趣味性,但任何一個有趣、有用的程序、項目或者遊戲,都須要堅實的基本功方能實現,設計模式就是咱們必學的基本功。

「每一棟大廈,都從一塊磚開始」

相關文章
相關標籤/搜索