常用設計模式與設計原則

I. 引言

設計模式(Design Pattern)是一套被反復使用灼伤、多數(shù)人知曉的、經(jīng)過分類的咪鲜、代碼設計經(jīng)驗的總結(jié)狐赡。

使用設計模式的目的:為了代碼可重用性、讓代碼更容易被他人理解疟丙、保證代碼可靠性颖侄。 設計模式使代碼編寫真正工程化;設計模式是軟件工程的基礎(chǔ)享郊,如同大廈的結(jié)構(gòu)一樣览祖。

創(chuàng)建型模式:對類的實例化過程的抽象。一些系統(tǒng)在創(chuàng)建對象時炊琉,需要動態(tài)地決定怎樣創(chuàng)建對象展蒂,創(chuàng)建哪些對象又活,以及如何組合和表示這些對象。創(chuàng)建模式描述了怎樣構(gòu)造和封裝這些動態(tài)的決定锰悼。包含類的創(chuàng)建模式和對象的創(chuàng)建模式柳骄。

結(jié)構(gòu)型模式:描述如何將類或?qū)ο蠼Y(jié)合在一起形成更大的結(jié)構(gòu)。分為類的結(jié)構(gòu)模式和對象的結(jié)構(gòu)模式箕般。類的結(jié)構(gòu)模式使用繼承把類耐薯,接口等組合在一起,以形成更大的結(jié)構(gòu)丝里。類的結(jié)構(gòu)模式是靜態(tài)的曲初。對象的結(jié)構(gòu)模式描述怎樣把各種不同類型的對象組合在一起,以實現(xiàn)新的功能的方法丙者。對象的結(jié)構(gòu)模式是動態(tài)的复斥。

行為型模式:對在不同的對象之間劃分責任和算法的抽象化。不僅僅是關(guān)于類和對象的械媒,并是關(guān)于他們之間的相互作用目锭。類的行為模式使用繼承關(guān)系在幾個類之間分配行為。對象的行為模式則使用對象的聚合來分配行為纷捞。

設計模式分為三種類型痢虹,共23種。

  • 創(chuàng)建型模式:單例模式主儡、抽象工廠模式奖唯、建造者模式、工廠模式糜值、原型模式丰捷。

  • 結(jié)構(gòu)型模式:適配器模式、橋接模式寂汇、裝飾模式病往、組合模式、外觀模式骄瓣、享元模式停巷、代理模式。

  • 行為型模式:模版方法模式榕栏、命令模式畔勤、迭代器模式、觀察者模式扒磁、中介者模式庆揪、備忘錄模式、解釋器模式妨托、狀態(tài)模式嚷硫、策略模式检访、責任鏈模式、訪問者模式仔掸。

設計模式分類

下面將對一些常用的設計模式和軟件設計的六大原則進行介紹。

一. 創(chuàng)建型模式

1. Factory method 工廠方法(工廠模式)

作用

一個類需要一個產(chǎn)品來完成某項工作医清,但它不能確定起暮,也不關(guān)心具體拿到什么產(chǎn)品,因此它定義一個工廠方法会烙,將具體產(chǎn)品的生產(chǎn)延遲到子類決定负懦。

實現(xiàn)

工廠模式
  1. 父類可以選擇為工廠方法提供一個默認的實現(xiàn);
  2. 工廠方法通常在模板方法(Template method)中被調(diào)用柏腻,上圖中AnOperation()就是一個模板方法纸厉。

2. Abstract factory 抽象工廠

作用

系統(tǒng)有一組相互關(guān)聯(lián)的產(chǎn)品接口,及幾套不同的實現(xiàn)五嫂】牌罚客戶只依賴產(chǎn)品接口,并需要能靈活地在幾套實現(xiàn)中切換沃缘。

因此提供一個抽象工廠生產(chǎn)抽象的產(chǎn)品躯枢,每個產(chǎn)品在其中都對應一個工廠方法,產(chǎn)品族的每一套實現(xiàn)都提供一個具體工廠槐臀〕澹客戶通過抽象工廠獲取產(chǎn)品,當需要切換到產(chǎn)品的其他實現(xiàn)時只需要更換工廠的實現(xiàn)類水慨。

實現(xiàn)

抽象工廠

應用

根據(jù)底層數(shù)據(jù)源的不同得糜,DAO的實現(xiàn)通常有幾套,當切換數(shù)據(jù)源時晰洒,系統(tǒng)使用的DAO的實現(xiàn)也應當能快速切換朝抖。這是使用抽象工廠的一個典型場景。

3. Singleton 單例

作用

保證一個類只有一個對象

實現(xiàn)

  1. private構(gòu)造器
  2. private static 類變量 singleton
  3. public static 類方法 getInstance() 返回singleton欢顷。

實例化時機:

  1. eager
  2. lazy

lazy init 多線程問題的解決辦法:Double Check

private volatile static A singleton = null;

public static A getInstance(){
    if(singleton == null){
        sychronized(A.class){
            if(singleton == null) singleton = new A();
        }
    }
    return singleton;
}

private A(){}
  1. 為什么要第二次的null判斷槽棍?
    在第一次判null / 獲取鎖之間可能有其他線程實例化了。
  2. 為什么要volatile抬驴?
    在上面提到的情況下炼七,如果沒有volatile保證的可見性,在第二次null判斷時當前線程可能看不到別的線程創(chuàng)建的對象布持,從而通過并再創(chuàng)建一次豌拙。

static 內(nèi)部類利用 “類的加載/static塊是線程安全的” 實現(xiàn)線程安全的lazy init:

public class A{
    private static class Holder{
        private static A singleton = new A();
    }

    public static A getInstance(){
        return Holder.singleton;
    }

    private A(){}
}

4. Builder 建造者模式

作用

你有一個產(chǎn)品,該產(chǎn)品由若干part裝配而成题暖,裝配的邏輯是固定的按傅,但各個part的構(gòu)造是可切換選擇的捉超,Builder模式將 固定的裝配邏輯易變的part構(gòu)造邏輯 分離開,可以方便地在不同的part實現(xiàn)邏輯之間切換唯绍。

實現(xiàn)

建造者模式
  1. Director#construct() 負責固定的裝配邏輯拼岳;
  2. 一個Builder實例負責一個產(chǎn)品內(nèi)部所有part的構(gòu)造(buildPart()方法族),并向外部暴露方法况芒,在part都裝配完畢后獲取該產(chǎn)品惜纸。

交互

建造者模式交互

5. Prototype 原型模式

作用

用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象绝骚。

適用性

  • 當要實例化的類是在運行時刻指定時耐版,例如,通過動態(tài)裝載压汪;

  • 為了避免創(chuàng)建一個與產(chǎn)品類層次平行的工廠類層次時粪牲;

  • 當一個類的實例只能有幾個不同狀態(tài)組合中的一種時。建立相應數(shù)目的原型并克隆它們可能比每次用合適的狀態(tài)手工實例化該類更方便一些止剖。

實現(xiàn)

原型模式

二. 結(jié)構(gòu)型模式

1. Adapter 適配器

作用

在兩個不兼容的接口之間加一個中間層腺阳,用組合的方式將一個現(xiàn)有對象匹配到需要的接口。

Convert the interface of a class into another interface the client expects

實現(xiàn)

適配器模式

2. Proxy 代理

作用

Provide a surrogate or place holder for another object to control access to it

你有一個真正干活的對象RealSubject滴须,但需要向client控制對他的訪問舌狗,比如權(quán)限的控制 / Lazy load / 結(jié)果的緩存等等,因此在client和RealSubject之間增加一個中間層Proxy代替RealSubject扔水,Proxy包裹RealSubject痛侍,將具體功能實現(xiàn)委托給它,并在RealSubject執(zhí)行真正的功能前后插入自己的邏輯魔市;此外主届,Proxy向client隱藏了RealSubject的存在。

實現(xiàn)

代理模式

Decorator模式的區(qū)別

Proxy與Decorator有著相似的結(jié)構(gòu)待德,** 他們都在client和真實對象之間增加一個與真實對象實現(xiàn)了相同接口的中間層君丁,這個中間層保留了對真實對象的引用并向他們發(fā)送請求**。然而他們的設計目的是不同的:

Decorator側(cè)重動態(tài)為實體增加功能将宪,因此在該模式中:

  1. 實體只實現(xiàn)了部分功能绘闷,Decorator實現(xiàn)了其他的增強功能;
  2. 支持遞歸組合(增加多重功能)较坛;
  3. Decorator不知道自己裝飾的是哪個具體對象印蔗,client必須自己手動將實體和Decorator關(guān)聯(lián)起來。

Proxy的目的則是當訪問一個特定實體不方便或不符合要求時丑勤,為這個實體提供一個替代者华嘹,因此:

  1. 實體實現(xiàn)了關(guān)鍵功能,Proxy提供(或拒絕)對它的訪問法竞;
  2. 不支持遞歸組合耙厚;
  3. Proxy向client屏蔽RealSubject的存在强挫,client只能拿到Proxy;
  4. Proxy確定地知道自己的代理目標是RealSubject薛躬,因此它和RealSubject相關(guān)聯(lián)而不是Subject接口俯渤;此外,它們的關(guān)系是靜態(tài)的型宝,無法在運行時改變Proxy代理的目標對象稠诲。

3. Bridge 橋接模式

作用

你有一個產(chǎn)品,它在兩個維度上都是可變化的诡曙,如果用繼承,則需要n*m個子類略水。Bridge模式將兩個維度的繼承體系獨立出來价卤,并在二者之間用組合進行裝配,避免類的泛濫渊涝。

進一步地考慮慎璧,一個產(chǎn)品的繼承體系應該只有一個維度,如果出現(xiàn)了其他維度上的繼承跨释,要考慮該維度是否是行為/實現(xiàn)相關(guān)的胸私。對于行為/實現(xiàn)方面的變化,應當先把行為獨立地抽象出來鳖谈,并與原產(chǎn)品組合(這就是策略模式的含義)岁疼,而不應該直接在原產(chǎn)品上通過繼承表達該行為的變化。

舉個例子缆娃,假如系統(tǒng)內(nèi)要發(fā)送消息捷绒,消息按迫切程度分為普通/加急/特急,消息的發(fā)送形式也可以多樣贯要,比如站內(nèi)信/短信/email暖侨,每種消息都要求可以用任意方式發(fā)送:

發(fā)送消息

如果簡單地用繼承,則需要33 = 9個類崇渗。但實際上字逗,消息的發(fā)送* 這個維度屬于行為,不要用繼承來表達行為的變化宅广,這樣會污染原本的抽象層次葫掉,應當用策略模式消息發(fā)送 這個行為分離。

采用Bridge模式:


Bridge模式

實現(xiàn)

橋接模式

產(chǎn)品的抽象 + 行為的分離(策略模式

總結(jié)

Bridge模式在我看來是對策略模式的擴展乘碑,它的核心有兩點:

  1. 只在一個維度上用繼承挖息,出現(xiàn)了多個維度則考慮分離并用組合,避免類的泛濫和抽象維度的混雜兽肤;
  2. 策略模式隔離行為的變化套腹,不要讓行為/實現(xiàn)的變化污染原本的繼承體系绪抛。

4. Decorator 裝飾者

作用

有一系列產(chǎn)品,你希望動態(tài)地為他們添加額外 / 可自由組合 的功能电禀,并且不影響產(chǎn)品本身幢码。

Attach additional responsibilities to an object dynamically.

實現(xiàn)

裝飾者模式
  1. Decorator 裝飾器繼承產(chǎn)品抽象接口尖飞,并在內(nèi)部持有一個產(chǎn)品(可能是具體產(chǎn)品,也有可能被裝飾過了)贞铣;
  2. Decorator的具體實現(xiàn),為其裝飾的產(chǎn)品提供額外的功能沮明,類似遞歸的調(diào)用;
  3. 可以同時反復應用多個 Decorator 酱畅,實現(xiàn)額外功能的動態(tài)組合。

應用

  1. java的IO流的設計是一個典型的裝飾者模式:


    IO Stream設計

ByteArrayInputStream | FileInputStream | ObjectInputStream | StringBufferInputStream是具體的輸入流產(chǎn)品江场,根據(jù)數(shù)據(jù)來源區(qū)分;
FilterInputStream是裝飾器餐蔬;
BufferedInputStream | DataInputStream | LineNumberInputStream | PushbackInputStream是具體的裝飾器在张,分別為其他輸入流提供緩沖/類型讀寫/跟蹤行號/退回已讀數(shù)據(jù)的功能帮匾,這些裝飾器是可以組合使用的:

InputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("test.txt"))); 
  1. Decorator模式也可以用來實現(xiàn)AOP的類似功能(雖然實際大部分都是用JDK動態(tài)代理 / 運行時修改字節(jié)碼)瘟斜,Decorator的具體實現(xiàn)就是我們想要獨立出來的切面,產(chǎn)品的具體實現(xiàn)則是我們想要保持獨立的業(yè)務邏輯虽惭。

5. Composite 組合模式

作用

實現(xiàn)樹形結(jié)構(gòu)芽唇,并讓用戶可以用統(tǒng)一的接口對待葉子節(jié)點和非葉子節(jié)點匆笤。

實現(xiàn)

組合模式
  1. 操作孩子的方法應該放在Component中嗎炮捧?畢竟Leaf是不支持這些操作的庶诡。
    出于透明性考慮末誓,應該放在Component中喇澡,Leaf對這些方法就提供一個空的實現(xiàn)殊校。
  2. Component除了保存孩子箩艺,也可以記錄父親艺谆;

應用

UI / 人員組織管理這種典型的樹形結(jié)構(gòu)中用的比較廣泛静汤。

6. Facade 門面模式

作用

一個系統(tǒng)對外提供服務虫给,系統(tǒng)暴露的接口應該是簡單而統(tǒng)一的侠碧,客戶不應該直接和系統(tǒng)內(nèi)復雜的子部件進行交互弄兜,而應只依賴于一個單一的高層接口替饿,該組件為客戶屏蔽了內(nèi)部的復雜性视卢,降低了客戶和系統(tǒng)的耦合据过。

門面模式

更像是一種設計思路,而非一個具體模式饥漫。


三. 行為模式

1. Chain of Responsibility 責任鏈

作用

客戶端發(fā)出一個請求庸队,有一系列的處理器都有機會處理這個請求闯割,但具體哪個是運行時決定的宙拉,客戶端也不知道究竟誰會來處理谢澈。

因此將所有處理器組成一個鏈條锥忿,將請求從鏈條中流過敬鬓,每個處理器查看是否應該處理它,如果不是础芍,則交給后面的處理器仑性,否則處理并退出虏缸。處理器在鏈中的位置決定其優(yōu)先級刽辙。

將請求者和處理者解耦宰缤,可以動態(tài)切換/組合處理者慨灭。

實現(xiàn)

責任鏈模式

擴展

客戶端發(fā)出一個請求氧骤,請求的處理分為很多步驟筹陵,這些步驟是不確定的/可以動態(tài)組合的朦佩,甚至需要支持在運行時改變步驟,或者在步驟間任意跳轉(zhuǎn)宋彼。

解決方案和責任鏈類似输涕,將處理流程抽象為一個處理器鏈條占贫,鏈條的組裝交給外部決定。每個處理器對請求完成自己負責的業(yè)務邏輯碉京,并看情況結(jié)束/傳遞給下一個處理器/跳轉(zhuǎn)到任意處理器谐宙。

這和標準的責任鏈的結(jié)構(gòu)基本一樣凡蜻,但他們的目的不一樣划栓。標準責任鏈目的是動態(tài) 找到請求的處理者 忠荞;擴展(某些地方稱為“功能鏈”委煤?)則是為了獲取 動態(tài)拼裝和改變處理流程 的能力碧绞。

應用

標準責任鏈

UI中的事件冒泡機制是責任鏈的一個典型應用讥邻。HTML中,點擊一個DOM元素袜香,產(chǎn)生的click事件將依次冒泡給它的父元素蜈首,每個父元素上都可以注冊對click事件的監(jiān)聽器欢策,監(jiān)聽器中除了對事件處理外踩寇,也可以結(jié)束事件的繼續(xù)冒泡俺孙。

擴展(功能鏈)
  1. Web應用中的各種filter/攔截器睛榄;
  2. Netty中的pipeline

2. Command 命令

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

你需要向一個對象提交請求场靴,但對請求的處理是動態(tài)的旨剥,無法寫死轨帜。比如一個菜單項阵谚,在不同的上下文中梢什,點擊它要做的事情顯然是不一樣的嗡午。

Command模式的思路是 抽象請求(及處理)

命令模式
  1. Client 裝配 InvokerCommand狸演,** 如果需要不同的處理宵距,裝配不同的Command即可 **;
  2. ClientInvoker 發(fā)出請求;
  3. Invoker 將請求的處理委托給 Command#execute()满哪。

很多時候Command不夠智能哨鸭,自己無法處理請求像鸡,需要將請求委托給另一個Receiver進行真正的處理只估,ConcreteCommand可以認為是Receiver的適配器:

Command適配器

可以看到蛔钙,Command模式的最大價值在于:隔離 請求的接收者請求的處理邏輯
此外子漩,將請求及其處理邏輯抽象為Command后可以做很多有意思的事情:

1. 可撤銷的操作
在Command接口中增加一個接口 undo() 實現(xiàn)單個命令的撤銷動作幢泼,并用一個stack保存所有Command缕棵;當用戶觸發(fā)撤銷時依次從stack pop出最近的Command招驴,執(zhí)行其undo()方法别厘。

2. 宏命令
宏命令實質(zhì)是個樹形結(jié)構(gòu)氮发,對Command應用Composite 組合模式即可實現(xiàn):

宏命令實現(xiàn)

3. 排隊
4. 日志記錄和恢復

3. Memento 備忘錄

有些情況下你需要記錄一個對象(稱為Originator)在某個時刻的狀態(tài)(snapshot)爽冕,以便后續(xù)恢復颈畸,我們可以用一個類Memento表示snapshot承冰,它包含了Originator的部分或全部狀態(tài):

備忘錄模式
  1. Originator 負責創(chuàng)建Memento,以及恢復到某個Memento娜搂;
  2. Memento 即Originator的snapshot百宇;
  3. Caretaker 充當協(xié)調(diào)者携御,它負責向Originator請求當前Memento / 保存Memento / 在后續(xù)某個時刻讓Originator恢復到某個Memento啄刹。

但這里有一個問題誓军,為了隱藏Originator的實現(xiàn)細節(jié)昵时,Memento必須向外部隱藏內(nèi)部數(shù)據(jù)壹甥,即不開放state 的 getter/setter 給外部盹廷,但這樣一來俄占,Originator也無法創(chuàng)建Memento了渤弛。

為了解決這個問題她肯,在Memento模式的一般實現(xiàn)中晴氨,Memento 類被分為兩個部分:

備忘錄
  1. 標記接口 Memento籽前,空的枝哄,Caretaker只能得到這個接口挠锥;
  2. Memento的真正實現(xiàn)MementoImpl,作為Originator私有內(nèi)部類 蓖宦,這樣既允許Originator訪問Memento的內(nèi)部狀態(tài)球昨,又滿足了Memento向外部(主要是Caretaker)隱藏內(nèi)部細節(jié)的要求主慰。

如果對 Memento 的封裝性沒有嚴格的要求共螺,第一種實現(xiàn)顯然更簡單藐不。

4. Observer 觀察者

作用

定義一個一對多關(guān)系,在Subject狀態(tài)發(fā)生改變時挑秉,所有Observer獲得通知犀概。

解耦 事件發(fā)生者 & 事件接收者倘零,使得雙方的改動互不影響产喉,關(guān)聯(lián)關(guān)系也可動態(tài)改變。

實現(xiàn)

觀察者模式

數(shù)據(jù)傳遞的兩種方式:

  1. 推:由 Subject 主動向 Observer 推送信息晦譬,而不管信息對后者而言是否需要/是否足夠敛腌。
  2. 拉:Subject 把自己傳遞給 Observer,由 Observer 從 Subject 拉取自己需要的信息惫皱。

擴展: Observer 注冊時可以指定自己感興趣的事件像樊。

擴展:EventBus

傳統(tǒng)的Observer模式中,事件發(fā)生者和接收者依然存在耦合旅敷,發(fā)生者需要管理接收者的集合生棍,我們可以進一步地,在Subject和Observer間增加一個中間層負責轉(zhuǎn)發(fā)事件媳谁,將它們徹底地解耦友酱;進一步,這個事件轉(zhuǎn)發(fā)者可以是通用的柔纵,支持任意發(fā)布者和接受者缔杉,通常稱之為EventBus,是一種廣泛應用的架構(gòu)搁料。

5. State 狀態(tài)模式

作用

模擬狀態(tài)機或详,描述一個對象(Context)的狀態(tài)變遷,將特性狀態(tài)下的行為分割開來郭计,避免在Context中用大量的if維護所有狀態(tài)的變遷霸琴,而且容易擴展新的狀態(tài)。

實現(xiàn)

狀態(tài)模式
  1. Context中記錄它自己當前的狀態(tài)昭伸;
  2. Context接收一個輸入動作沈贝,并將該輸入委托給當前所處State處理;
  3. State處理輸入勋乾,根據(jù)需要讓Context躍遷到另一狀態(tài)宋下。

如果State不保存狀態(tài)則可以是單例的,Java中辑莫,可以用enum類型實現(xiàn)State学歧。

6. Strategy 策略模式

作用

你有一個對象負責完成某件事情,但在不同時刻其使用的算法是不同的各吨,Strategy模式將可變的算法獨立并封裝枝笨,避免大量if條件判斷,并方便替換和擴展揭蜒。

Strategy 封裝了 相同行為的不同實現(xiàn)

實現(xiàn)

策略模式

Strategy的實現(xiàn)通常依賴Context的數(shù)據(jù)横浑,后者在調(diào)用前者的方法時需要將自己傳遞過去。

實際應用中屉更,經(jīng)常會發(fā)現(xiàn)不同的策略其算法骨架類似徙融,只有某些具體步驟不同,此時可以對Strategy應用Template Method模式瑰谜。

7. Template Method 模板方法

作用

將一個算法的通用骨架抽象到父類以避免代碼重復欺冀,而將一些可變的步驟延遲到子類,子類不用關(guān)心算法結(jié)構(gòu)萨脑,只需關(guān)注自己需要實現(xiàn)的特定步驟隐轩。

實現(xiàn)

模板方法

這個沒什么好說的。


四. 設計原則

  1. SRP原則 - 單一職責原則(Single Responsibility Principle)

    每個類實現(xiàn)單一職責渤早,并且單一職責都有清楚明確的定義职车,有利于降低軟件的復雜性, 提高可讀性、可維護性和可擴展性悴灵。

    軟件設計應遵守單一職責原則军援,將不同的職責封裝到不同的類或模塊中。

  2. OCP法則 - 開放-關(guān)閉原則

    一個類應當對擴展開放称勋,對修改關(guān)閉。即當有新的需求時涯竟,不是修改已有的類赡鲜,而是對已有的類進行擴展。

    • 通過擴展已有軟件系統(tǒng)庐船,可以提供新的行為银酬,以滿足對軟件的新的需求,使變化中的軟件有一定的適應性和靈活性筐钟。
    • 已有軟件模塊揩瞪,特別是最重要的抽象層模塊不能再修改,這使變化中的軟件系統(tǒng)有一定的穩(wěn)定性和延續(xù)性篓冲。
      實現(xiàn)開閉原則的關(guān)鍵在于 分離不變和變化的部分李破,并對變化的部分進行合理的高層抽象,并讓不變的部分依賴該高層抽象壹将,這樣就能在不同的實現(xiàn)間切換嗤攻,或者擴展新的實現(xiàn)。很多設計模式都體現(xiàn)了這一點诽俯,比如策略模式將算法抽象出來妇菱,模板方法將不變的算法骨架與易變的需要自定義的步驟隔離,裝飾者模式將不變的核心功能對象和易變的增強功能隔離等等暴区。
  3. LSP法則 - 里氏替換原則(Liskov Substitution Principle)
    把抽象接口和實現(xiàn)分離,子類必須能替換掉父類闯团,這個原則通常由語言保證。

  4. DIP法則 - 依賴倒置原則(Dependence Inversion Principle)
    抽象不應當依賴于細節(jié)仙粱;細節(jié)應當依賴于抽象房交;要針對接口編程,不針對實現(xiàn)編程伐割。具體講就是要依賴于抽象涌萤,不要依賴于具體。
    高層不直接依賴底層口猜,而是高層定義自己需要底層提供什么樣的接口负溪,底層負責實現(xiàn),這樣就可以隨意切換底層的具體實現(xiàn)而不用影響高層济炎,但底層反而要依賴高層公布的接口川抡,所以稱為“依賴倒置”。

  5. ISP原則 - 接口分離原則 (Interface Segregation Principle)
    每一個接口應該是一種角色,不多不少崖堤,不干不該干的事侍咱,該干的事都要干。這類似編碼原則中的最小權(quán)限法則密幔。軟件設計不應出現(xiàn)龐大的接口楔脯,迫使客戶在使用時必須從一大堆它不需要的方法中尋找目的方法。這樣的接口應該按照不同客戶的需求被分離成若干小接口胯甩。

  6. LKP原則 - 最少知識原則(Least Knowledge Principle)

    也稱為迪米特法則昧廷。原則的核心思想即一個對象應對其他對象有盡可能少的了解。

    類應當只與自己的朋友交互偎箫。該原則的思想是木柬,將類對外部的了解盡量保持在一定范圍內(nèi),盡量減少類之間的交互淹办,從而降低各個組件間的耦合眉枕。

    “朋友”的定義:

    • 當前對象的屬性
    • 當前對象所創(chuàng)建的對象
    • 方法參數(shù)傳遞進來的參數(shù)
    • 方法內(nèi)創(chuàng)建的對象

五. 參考與推薦

  • 《大話設計模式》
  • 《深入淺出設計模式》
  • 《Java與模式》
  • 《敏捷軟件開發(fā)原則、模式與實踐》
  • 《設計模式--可復用面向?qū)ο筌浖幕A(chǔ)》
  • 《設計模式精解》
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末怜森,一起剝皮案震驚了整個濱河市速挑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌副硅,老刑警劉巖梗摇,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異想许,居然都是意外死亡伶授,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門流纹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來糜烹,“玉大人,你說我怎么就攤上這事漱凝〈模” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵茸炒,是天一觀的道長愕乎。 經(jīng)常有香客問我,道長壁公,這世上最難降的妖魔是什么感论? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮紊册,結(jié)果婚禮上比肄,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好芳绩,可當我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布掀亥。 她就那樣靜靜地躺著,像睡著了一般妥色。 火紅的嫁衣襯著肌膚如雪搪花。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天嘹害,我揣著相機與錄音撮竿,去河邊找鬼。 笑死吼拥,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的线衫。 我是一名探鬼主播凿可,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼授账!你這毒婦竟也來了枯跑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤白热,失蹤者是張志新(化名)和其女友劉穎敛助,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屋确,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡纳击,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了攻臀。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片焕数。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖刨啸,靈堂內(nèi)的尸體忽然破棺而出堡赔,到底是詐尸還是另有隱情,我是刑警寧澤设联,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布善已,位于F島的核電站,受9級特大地震影響离例,放射性物質(zhì)發(fā)生泄漏换团。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一宫蛆、第九天 我趴在偏房一處隱蔽的房頂上張望啥寇。 院中可真熱鬧,春花似錦、人聲如沸辑甜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽磷醋。三九已至猫牡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邓线,已是汗流浹背淌友。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留骇陈,地道東北人震庭。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像你雌,于是被迫代替她去往敵國和親器联。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容