1. 程式人生 > >設計模式之類之間的關係和六大原則

設計模式之類之間的關係和六大原則

1 類之間的關係

類與類之間的關係大概有6種,要看懂UML圖,首先需要了解這幾種關係。

1.1 繼承關係

繼承指的是一個類(稱為子類,子介面)繼承另外的一個類(成為父類,父介面)的功能,並可以增加它自己的新功能的能力。在UML類圖設計中,繼承用一條帶空心三角箭頭的實線表示,從子類指向父類,或者子介面指向父介面。

在這裡插入圖片描述

1.2 實現關係

實現指的是一個class類實現interface介面(可以是多個)的功能,實現是類與介面之間最常見的關係。在Java中此類關係是通過關鍵字implements明確標識,在設計時一般沒有爭議性。而在C++中並沒有介面的關鍵字,這種關係一般是通過宣告純虛擬函式來實現。在UML類圖設計中,實現是用一條帶空心三角箭頭的虛線表示,從類指向實現的介面。

在這裡插入圖片描述

1.3 依賴關係

簡單的理解,依賴就是一個類A使用到了另一個類B,而這種使用關係是具有偶然性的、臨時性的、非常弱的,但是B類的變化會影響到類A。比如某人要過河,需要借用一條船,此時人與船之間的關係就是依賴。表現在程式碼層面,為類B作為引數被類A在某個method方法中使用。在UML類圖設計中,依賴關係用由類A指向類B的帶箭頭虛線表示。

在這裡插入圖片描述

1.4 關聯關係

關聯體現的是兩個類之間語義級別的一種強依賴關係,比如我和我的朋友,這種關係比依賴更強、不存在依賴關係的偶然性、關係也不是臨時性的,一般是長期性的,而且雙方的關係一般是平等的。關聯可以是單向、雙向的。表現在程式碼層面,為被關聯類B以類的屬性形式出現在關聯類A中,也可能是關聯類A引用了一個型別為被關聯類B的全域性變數。在UML類圖設計中,關聯關係用由關聯類A指向被關聯類B的帶箭頭實線表示,在關聯的兩端可以標註關聯雙方的角色和多重性標記。
在這裡插入圖片描述

1.5 聚合關係

聚合關係是關聯關係的一種特例,它體現的是整體與部分的關係,即has-a關係。此時整體與不放呢之間是可分離的,它們可以具有各自的生命週期,部分可以屬於多個整體物件,也可以為多個整體物件共享。比如人群和單個人的關係,雁群與但只雁的關係。表現在程式碼層面,和關聯關係是一致的,只能從語義級別來區分。在UML類圖設計中,聚合關係以空心菱形加實線箭頭表示。

在這裡插入圖片描述

1.6 組合關係

組合也是關聯關係的一種特例,它體現的是一種contains-a的關係,這種關係比聚合關係更強,也成為強聚合。它同樣體現在整體與部分的關係,但此時整體與部分是不可分的,整體的生命週期結束也就以為著部分的生命週期結束,比如人和人的大腦。表現在程式碼層面,和關聯關係是一致的,只能從語義級別來區分。在UML類圖設計中,組合關係以實心菱形加實線箭頭表示。
在這裡插入圖片描述

1.7 總結

對於繼承、實現這兩種關係沒多少疑問,它們體現的是一種類和類、或者類與介面間的縱向關係。其他的四種關係體現的是類和類或者類與介面間的引用、橫向關係。相對來說比較難以區分。這四種關係都是語義級別的,所以從程式碼層面並不能完全區分各種關係,但總的來說,後幾種關係所表現的強弱程度一次為:組合>聚合>關聯>依賴。

2 六大原則

2.1 單一職責原則

單一職責原則指的是對於一個類而言,應該僅有一個引起它變化的原因。如果一個類承擔的職責過多,就等於把這些職責耦合在一起,一個職責的變化可能會削弱或者一致這個類完成其他職責的能力。這種耦合會導致脆弱的設計,當變化發生時,設計會遭受到意向不到的破壞。

同樣的軟體設計真正要做的許多內容,就是發現職責並把那些職責相互分離。其實要去判斷是否應該分離出類來,也不難,那就是如果你能夠想到多於一個的動機去改變一個類,那麼這個類就具有多於一個的職責,就應該考慮類的職責分離。

2.2 開放-封閉原則

開放-封閉原則,是說軟體實體(類、模組、函式等等)應該可以擴充套件,但是不可以修改。這個原則其實有兩個特徵,一個是說對於擴充套件是開放的,另一個是說對於更改是封閉的。

但是無論模組是多麼的‘封閉’,都會存在一些無法對之封閉的變化。既然不可能完全封閉,設計人員必須對於他設計的模組應該對哪種變化封閉做出選擇。他必須先猜測出最有可能發生的變化種類,然後構造抽離來隔離那些變化。在我們最初編寫程式碼時,假設變化不會發生。當變化發生時,我們就建立抽象來隔離以後發生的同類變化。面對需求,對程式的改動是通過增加新程式碼進行的,而不是更改現有的程式碼。

開發-封閉原則是面向物件設計的核心所在。遵循這個原則可以帶來面向物件技術所生成的巨大好處,也就是可維護、可擴充套件、可服用、靈活性好。開發人員應該僅對程式中呈現出頻繁變化的那些部分做出抽象,然而,對於應用程式中的每個部分都刻意地進行抽象同樣不是一個好注意。拒絕不成熟的抽象和抽象本身一樣重要。

2.3 依賴倒轉原則

依賴倒轉原則,簡單地說就是抽象不應該依賴細節,細節應該依賴於抽象,就是要針對介面程式設計,不要對實現程式設計。依賴倒轉原則:高層模組不應該依賴底層模組,兩個都應該依賴抽象。抽象不應該依賴細節,細節應該依賴抽象。例如:主機板、CPU、記憶體、硬碟都是在針對介面設計的,如果針對實現來設計,記憶體就要對應到具體的某個品牌的主機板,那就會出現換記憶體需要把主機板也換了的尷尬。這個原則很好理解,不過多贅述。

2.4 里氏代換原則

里氏代換原則是一個軟體實體如果使用的是一個父類的話,那麼一定適用於其子類,而且它覺察不出父類物件和子類物件的區別。也就是說,在軟體裡面,把父類都替換成它的子類,程式的行為沒有變化,簡單地說,子型別必須能夠替換掉它們的父型別。

2.5 介面隔離原則

使用多個專門的介面,而不使用單一的總介面,即客戶端不應該依賴那些它不需要的介面。根據介面隔離原則,當一個介面太大時,我們需要將它分割成一些更小的介面,使用該介面的客戶端僅需要知道與之相關的方法即可。每一個介面應該承擔一種相對獨立的角色,不幹不該乾的事,該乾的事都要幹。也就是說介面的定義要遵從單一職責原則。

2.6 迪米特法則

迪米特法則也叫最少知識原則。一個物件應該對其他物件保持最少的瞭解。如果兩個類不必彼此直接通訊,那麼這兩個類就不應當發生直接的相互作用。如果其中一個類需要呼叫另一個類的某一個方法的話,可以通過第三者轉發這個呼叫。

迪米特法則首先強調的前提是在類的結構設計上,每一個類都應當儘量降低成員的訪問許可權,也就是說,一個類包裝好自己的private狀態,不需要讓別額類知道的欄位或行為就不要公開。迪米特法則其根本思想,是強調了類之間的鬆耦合。類之間的耦合越弱,越有利於複用,一個處在弱耦合的類被修改,不會對有關係的類造成波及。

3 各種設計模式

常用的設計模式共有24種類,根據主要用途分為三類:建立型模式、結構型模式、行為型模式。也分為類模式和物件模式。如下圖:

設計模式

下面是各種設計模式的介紹:

策略模式

裝飾模式

代理模式

原型模式

外觀模式

建造者模式

觀察者模式

狀態模式

介面卡模式

備忘錄模式

組合模式

迭代器模式

單例模式

橋接模式

命令模式

責任鏈模式

中介者模式

享元模式

直譯器模式

訪問者模式