<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] ## 6、面向對象的編程思維理解interface。 ### 一、 interface接口   interface 是GO語言的基礎特性之一。可以理解為一種類型的規范或者約定。它跟java,C# 不太一樣,不需要顯示說明實現了某個接口,它沒有繼承或子類或“implements”關鍵字,只是通過約定的形式,隱式的實現interface 中的方法即可。因此,Golang 中的 interface 讓編碼更靈活、易擴展。 如何理解go 語言中的interface ? 只需記住以下三點即可: 1. interface 是方法聲明的集合 2. 任何類型的對象實現了在interface 接口中聲明的全部方法,則表明該類型實現了該接口。 3. interface 可以作為一種數據類型,實現了該接口的任何對象都可以給對應的接口類型變量賦值。 >注意: >  a. interface 可以被任意對象實現,一個類型/對象也可以實現多個 interface >  b. 方法不能重載,如 `eat(), eat(s string)` 不能同時存在 ```go package main import "fmt" type Phone interface { call() } type NokiaPhone struct { } func (nokiaPhone NokiaPhone) call() { fmt.Println("I am Nokia, I can call you!") } type ApplePhone struct { } func (iPhone ApplePhone) call() { fmt.Println("I am Apple Phone, I can call you!") } func main() { var phone Phone phone = new(NokiaPhone) phone.call() phone = new(ApplePhone) phone.call() } ``` 上述中體現了`interface`接口的語法,在`main`函數中,也體現了`多態`的特性。 同樣一個`phone`的抽象接口,分別指向不同的實體對象,調用的call()方法,打印的效果不同,那么就是體現出了多態的特性。 ### 二、 面向對象中的開閉原則 #### 2.1 平鋪式的模塊設計 那么作為`interface`數據類型,他存在的意義在哪呢? 實際上是為了滿足一些面向對象的編程思想。我們知道,軟件設計的最高目標就是`高內聚,低耦合`。那么其中有一個設計原則叫`開閉原則`。什么是開閉原則呢,接下來我們看一個例子: ```go package main import "fmt" //我們要寫一個類,Banker銀行業務員 type Banker struct { } //存款業務 func (this *Banker) Save() { fmt.Println( "進行了 存款業務...") } //轉賬業務 func (this *Banker) Transfer() { fmt.Println( "進行了 轉賬業務...") } //支付業務 func (this *Banker) Pay() { fmt.Println( "進行了 支付業務...") } func main() { banker := &Banker{} banker.Save() banker.Transfer() banker.Pay() } ``` 代碼很簡單,就是一個銀行業務員,他可能擁有很多的業務,比如`Save()`存款、`Transfer()`轉賬、`Pay()`支付等。那么如果這個業務員模塊只有這幾個方法還好,但是隨著我們的程序寫的越來越復雜,銀行業務員可能就要增加方法,會導致業務員模塊越來越臃腫。 ![](https://img.kancloud.cn/d5/1e/d51ee550c6de940b556f14e28e13969e_1024x768.png) ? 這樣的設計會導致,當我們去給Banker添加新的業務的時候,會直接修改原有的Banker代碼,那么Banker模塊的功能會越來越多,出現問題的幾率也就越來越大,假如此時Banker已經有99個業務了,現在我們要添加第100個業務,可能由于一次的不小心,導致之前99個業務也一起崩潰,因為所有的業務都在一個Banker類里,他們的耦合度太高,Banker的職責也不夠單一,代碼的維護成本隨著業務的復雜正比成倍增大。 #### 2.2 開閉原則設計 那么,如果我們擁有接口, `interface`這個東西,那么我們就可以抽象一層出來,制作一個抽象的Banker模塊,然后提供一個抽象的方法。 分別根據這個抽象模塊,去實現`支付Banker(實現支付方法)`,`轉賬Banker(實現轉賬方法)` 如下: ![](https://img.kancloud.cn/26/86/26861196a8409e28251d9cdaa167a627_1024x768.png) 那么依然可以搞定程序的需求。 然后,當我們想要給Banker添加額外功能的時候,之前我們是直接修改Banker的內容,現在我們可以單獨定義一個`股票Banker(實現股票方法)`,到這個系統中。 而且股票Banker的實現成功或者失敗都不會影響之前的穩定系統,他很單一,而且獨立。 所以以上,當我們給一個系統添加一個功能的時候,不是通過修改代碼,而是通過增添代碼來完成,那么就是開閉原則的核心思想了。所以要想滿足上面的要求,是一定需要interface來提供一層抽象的接口的。 golang代碼實現如下: ```go package main import "fmt" //抽象的銀行業務員 type AbstractBanker interface{ DoBusi() //抽象的處理業務接口 } //存款的業務員 type SaveBanker struct { //AbstractBanker } func (sb *SaveBanker) DoBusi() { fmt.Println("進行了存款") } //轉賬的業務員 type TransferBanker struct { //AbstractBanker } func (tb *TransferBanker) DoBusi() { fmt.Println("進行了轉賬") } //支付的業務員 type PayBanker struct { //AbstractBanker } func (pb *PayBanker) DoBusi() { fmt.Println("進行了支付") } func main() { //進行存款 sb := &SaveBanker{} sb.DoBusi() //進行轉賬 tb := &TransferBanker{} tb.DoBusi() //進行支付 pb := &PayBanker{} pb.DoBusi() } ``` 當然我們也可以根據`AbstractBanker`設計一個小框架 ```go //實現架構層(基于抽象層進行業務封裝-針對interface接口進行封裝) func BankerBusiness(banker AbstractBanker) { //通過接口來向下調用,(多態現象) banker.DoBusi() } ``` 那么main中可以如下實現業務調用: ```go func main() { //進行存款 BankerBusiness(&SaveBanker{}) //進行存款 BankerBusiness(&TransferBanker{}) //進行存款 BankerBusiness(&PayBanker{}) } ``` >再看開閉原則定義: >開閉原則:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 >簡單的說就是在修改需求的時候,應該盡量通過擴展來實現變化,而不是通過修改已有代碼來實現變化。 ### 三、 接口的意義 好了,現在interface已經基本了解,那么接口的意義最終在哪里呢,想必現在你已經有了一個初步的認知,實際上接口的最大的意義就是實現多態的思想,就是我們可以根據interface類型來設計API接口,那么這種API接口的適應能力不僅能適應當下所實現的全部模塊,也適應未來實現的模塊來進行調用。 `調用未來`可能就是接口的最大意義所在吧,這也是為什么架構師那么值錢,因為良好的架構師是可以針對interface設計一套框架,在未來許多年卻依然適用。 ### 四、 面向對象中的依賴倒轉原則 #### 4.1 耦合度極高的模塊關系設計 ![](https://img.kancloud.cn/fe/8d/fe8d82845c62f215d1e825aa02b4d139_1024x768.png) ```go package main import "fmt" // === > 奔馳汽車 <=== type Benz struct { } func (this *Benz) Run() { fmt.Println("Benz is running...") } // === > 寶馬汽車 <=== type BMW struct { } func (this *BMW) Run() { fmt.Println("BMW is running ...") } //===> 司機張三 <=== type Zhang3 struct { //... } func (zhang3 *Zhang3) DriveBenZ(benz *Benz) { fmt.Println("zhang3 Drive Benz") benz.Run() } func (zhang3 *Zhang3) DriveBMW(bmw *BMW) { fmt.Println("zhang3 drive BMW") bmw.Run() } //===> 司機李四 <=== type Li4 struct { //... } func (li4 *Li4) DriveBenZ(benz *Benz) { fmt.Println("li4 Drive Benz") benz.Run() } func (li4 *Li4) DriveBMW(bmw *BMW) { fmt.Println("li4 drive BMW") bmw.Run() } func main() { //業務1 張3開奔馳 benz := &Benz{} zhang3 := &Zhang3{} zhang3.DriveBenZ(benz) //業務2 李四開寶馬 bmw := &BMW{} li4 := &Li4{} li4.DriveBMW(bmw) } ``` 我們來看上面的代碼和圖中每個模塊之間的依賴關系,實際上并沒有用到任何的`interface`接口層的代碼,顯然最后我們的兩個業務 `張三開奔馳`, `李四開寶馬`,程序中也都實現了。但是這種設計的問題就在于,小規模沒什么問題,但是一旦程序需要擴展,比如我現在要增加一個`豐田汽車` 或者 司機`王五`, 那么模塊和模塊的依賴關系將成指數級遞增,想蜘蛛網一樣越來越難維護和捋順。 #### 4.2 面向抽象層依賴倒轉 ![](https://img.kancloud.cn/6e/e9/6ee9ff273b8768d22b483c9691d2ab9d_1024x768.png) 如上圖所示,如果我們在設計一個系統的時候,將模塊分為3個層次,抽象層、實現層、業務邏輯層。那么,我們首先將抽象層的模塊和接口定義出來,這里就需要了`interface`接口的設計,然后我們依照抽象層,依次實現每個實現層的模塊,在我們寫實現層代碼的時候,實際上我們只需要參考對應的抽象層實現就好了,實現每個模塊,也和其他的實現的模塊沒有關系,這樣也符合了上面介紹的開閉原則。這樣實現起來每個模塊只依賴對象的接口,而和其他模塊沒關系,依賴關系單一。系統容易擴展和維護。 我們在指定業務邏輯也是一樣,只需要參考抽象層的接口來業務就好了,抽象層暴露出來的接口就是我們業務層可以使用的方法,然后可以通過多態的線下,接口指針指向哪個實現模塊,調用了就是具體的實現方法,這樣我們業務邏輯層也是依賴抽象成編程。 我們就將這種的設計原則叫做`依賴倒轉原則`。 來一起看一下修改的代碼: ```go package main import "fmt" // ===== > 抽象層 < ======== type Car interface { Run() } type Driver interface { Drive(car Car) } // ===== > 實現層 < ======== type BenZ struct { //... } func (benz * BenZ) Run() { fmt.Println("Benz is running...") } type Bmw struct { //... } func (bmw * Bmw) Run() { fmt.Println("Bmw is running...") } type Zhang_3 struct { //... } func (zhang3 *Zhang_3) Drive(car Car) { fmt.Println("Zhang3 drive car") car.Run() } type Li_4 struct { //... } func (li4 *Li_4) Drive(car Car) { fmt.Println("li4 drive car") car.Run() } // ===== > 業務邏輯層 < ======== func main() { //張3 開 寶馬 var bmw Car bmw = &Bmw{} var zhang3 Driver zhang3 = &Zhang_3{} zhang3.Drive(bmw) //李4 開 奔馳 var benz Car benz = &BenZ{} var li4 Driver li4 = &Li_4{} li4.Drive(benz) } ``` #### 4.3 依賴倒轉小練習 > 模擬組裝2臺電腦, > --- 抽象層 ---有顯卡Card 方法display,有內存Memory 方法storage,有處理器CPU 方法calculate > --- 實現層層 ---有 Intel因特爾公司 、產品有(顯卡、內存、CPU),有 Kingston 公司, 產品有(內存3),有 NVIDIA 公司, 產品有(顯卡) > --- 邏輯層 ---1. 組裝一臺Intel系列的電腦,并運行,2. 組裝一臺 Intel CPU Kingston內存 NVIDIA顯卡的電腦,并運行 ```go /* 模擬組裝2臺電腦 --- 抽象層 --- 有顯卡Card 方法display 有內存Memory 方法storage 有處理器CPU 方法calculate --- 實現層層 --- 有 Intel因特爾公司 、產品有(顯卡、內存、CPU) 有 Kingston 公司, 產品有(內存3) 有 NVIDIA 公司, 產品有(顯卡) --- 邏輯層 --- 1. 組裝一臺Intel系列的電腦,并運行 2. 組裝一臺 Intel CPU Kingston內存 NVIDIA顯卡的電腦,并運行 */ package main import "fmt" //------ 抽象層 ----- type Card interface{ Display() } type Memory interface { Storage() } type CPU interface { Calculate() } type Computer struct { cpu CPU mem Memory card Card } func NewComputer(cpu CPU, mem Memory, card Card) *Computer{ return &Computer{ cpu:cpu, mem:mem, card:card, } } func (this *Computer) DoWork() { this.cpu.Calculate() this.mem.Storage() this.card.Display() } //------ 實現層 ----- //intel type IntelCPU struct { CPU } func (this *IntelCPU) Calculate() { fmt.Println("Intel CPU 開始計算了...") } type IntelMemory struct { Memory } func (this *IntelMemory) Storage() { fmt.Println("Intel Memory 開始存儲了...") } type IntelCard struct { Card } func (this *IntelCard) Display() { fmt.Println("Intel Card 開始顯示了...") } //kingston type KingstonMemory struct { Memory } func (this *KingstonMemory) Storage() { fmt.Println("Kingston memory storage...") } //nvidia type NvidiaCard struct { Card } func (this *NvidiaCard) Display() { fmt.Println("Nvidia card display...") } //------ 業務邏輯層 ----- func main() { //intel系列的電腦 com1 := NewComputer(&IntelCPU{}, &IntelMemory{}, &IntelCard{}) com1.DoWork() //雜牌子 com2 := NewComputer(&IntelCPU{}, &KingstonMemory{}, &NvidiaCard{}) com2.DoWork() } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看