11.裝飾模式(Decorator Pattern)
定義:Attach additional responsibilities to an object dynamically keeping the same interface.Decorators provide a flexible alternative to subclassing for extending functionality.(動態(tài)地給一個對象添加一些額外的職責粤剧。就增加功能來說,裝飾模式相比生成子類更為靈活臊旭。)
[圖片上傳失敗...(image-56a5f2-1530774668240)]
● Component抽象構件
Component是一個接口或者是抽象類,就是定義我們最核心的對象,也就是最原始的對象山憨,如上面的成績單拜轨。
注意:在裝飾模式中,必然有一個最基本扮惦、最核心谬泌、最原始的接口或抽象類充當Component抽象構件狡逢。
● ConcreteComponent 具體構件
ConcreteComponent是最核心、最原始乒疏、最基本的接口或抽象類的實現,你要裝飾的就是它饮焦。
● Decorator裝飾角色
一般是一個抽象類怕吴,做什么用呢?實現接口或者抽象方法县踢,它里面可不一定有抽象的方法呀转绷,在它的屬性里必然有一個private變量指向Component抽象構件。
● 具體裝飾角色
ConcreteDecoratorA和ConcreteDecoratorB是兩個具體的裝飾類硼啤,你要把你最核心的议经、最原始的、最基本的東西裝飾成其他東西,上面的例子就是把一個比較平庸的成績單裝飾成家長認可的成績單煞肾。
使用場景:
● 需要擴展一個類的功能咧织,或給一個類增加附加功能。
● 需要動態(tài)地給一個對象增加功能籍救,這些功能可以再動態(tài)地撤銷习绢。
● 需要為一批的兄弟類進行改裝或加裝功能,當然是首選裝飾模式钧忽。
12.策略模式(Strategy Pattern)
定義:Define a family of algorithms,encapsulate each one,and make them interchangeable.(定義一組算法毯炮,將每個算法都封裝起來,并且使它們之間可以互換耸黑。)
[圖片上傳失敗...(image-3641a5-1530774668240)]
● Context封裝角色
它也叫做上下文角色桃煎,起承上啟下封裝作用,屏蔽高層模塊對策略大刊、算法的直接訪問为迈,封裝可能存在的變化。
● Strategy抽象策略角色
策略缺菌、算法家族的抽象葫辐,通常為接口,定義每個策略或算法必須具有的方法和屬性伴郁。各位看官可能要問了耿战,類圖中的AlgorithmInterface是什么意思,嘿嘿焊傅,algorithm是“運算法則”的意思剂陡,結合起來意思就明白了吧。
● ConcreteStrategy具體策略角色(多個)
實現抽象策略中的操作狐胎,該類含有具體的算法鸭栖。
使用場景:
● 多個類只有在算法或行為上稍有不同的場景。
● 算法需要自由切換的場景握巢。
● 需要屏蔽算法規(guī)則的場景晕鹊。
注意事項:具體策略數量超過4個,則需要考慮使用混合模式
策略模式擴展:策略枚舉
[](javascript:void(0); "復制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">public enum Calculator { //加法運算
ADD("+"){ public int exec(int a,int b){ return a+b;
}
}, //減法運算
SUB("-"){ public int exec(int a,int b){ return a - b;
}
};
String value = ""; //定義成員值類型
private Calculator(String _value){ this.value = _value;
} //獲得枚舉成員的值
public String getValue(){ return this.value;
} //聲明一個抽象函數
public abstract int exec(int a,int b);
}</pre>
](javascript:void(0); "復制代碼")
定義:
● 它是一個枚舉暴浦。
● 它是一個濃縮了的策略模式的枚舉溅话。
注意:
受枚舉類型的限制,每個枚舉項都是public歌焦、final公荧、static的,擴展性受到了一定的約束同规,因此在系統(tǒng)開發(fā)中循狰,策略枚舉一般擔當不經常發(fā)生變化的角色窟社。
致命缺陷:
所有的策略都需要暴露出去,由客戶端決定使用哪一個策略绪钥。
13.適配器模式(Adapter Pattern)
定義:Convert the interface of a class into another interface clients expect.Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.(將一個類的接口變換成客戶端所期待的另一種接口灿里,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。)
類適配器:
[圖片上傳失敗...(image-d10f57-1530774668240)]
● Target目標角色
該角色定義把其他類轉換為何種接口程腹,也就是我們的期望接口匣吊,例子中的IUserInfo接口就是目標角色。
● Adaptee源角色
你想把誰轉換成目標角色寸潦,這個“誰”就是源角色色鸳,它是已經存在的、運行良好的類或對象见转,經過適配器角色的包裝命雀,它會成為一個嶄新、靚麗的角色斩箫。
● Adapter適配器角色
適配器模式的核心角色吏砂,其他兩個角色都是已經存在的角色,而適配器角色是需要新建立的乘客,它的職責非常簡單:把源角色轉換為目標角色狐血,怎么轉換?通過繼承或是類關聯的方式易核。
使用場景:
你有動機修改一個已經投產中的接口時匈织,適配器模式可能是最適合你的模式。比如系統(tǒng)擴展了牡直,需要使用一個已有或新建立的類报亩,但這個類又不符合系統(tǒng)的接口,怎么辦井氢?使用適配器模式,這也是我們例子中提到的岳链。
注意事項:
詳細設計階段不要考慮使用適配器模式花竞,使用主要場景為擴展應用中。
對象適配器:
[圖片上傳失敗...(image-79762a-1530774668239)]
** 對象適配器和類適配器的區(qū)別:**
類適配器是類間繼承掸哑,對象適配器是對象的合成關系约急,也可以說是類的關聯關系,這是兩者的根本區(qū)別苗分。(實際項目中對象適配器使用到的場景相對比較多)厌蔽。
14.迭代器模式(Iterator Pattern)
定義:Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.(它提供一種方法訪問一個容器對象中各個元素,而又不需暴露該對象的內部細節(jié)摔癣。)
[圖片上傳失敗...(image-70d0c3-1530774668239)]
● Iterator抽象迭代器
抽象迭代器負責定義訪問和遍歷元素的接口奴饮,而且基本上是有固定的3個方法:first()獲得第一個元素纬向,next()訪問下一個元素,isDone()是否已經訪問到底部(Java叫做hasNext()方法)戴卜。
● ConcreteIterator具體迭代器
具體迭代器角色要實現迭代器接口逾条,完成容器元素的遍歷。
● Aggregate抽象容器
容器角色負責提供創(chuàng)建具體迭代器角色的接口投剥,必然提供一個類似createIterator()這樣的方法师脂,在Java中一般是iterator()方法。
● Concrete Aggregate具體容器
具體容器實現容器接口定義的方法江锨,創(chuàng)建出容納迭代器的對象吃警。
ps:迭代器模式已經被淘汰,java中已經把迭代器運用到各個聚集類(collection)中了啄育,使用java自帶的迭代器就已經滿足我們的需求了酌心。
15.組合模式((Composite Pattern))
定義:Compose objects into tree structures to represent part-whole hierarchies.Composite lets clients treat individual objects and compositions of objects uniformly.(將對象組合成樹形結構以表示“部分-整體”的層次結構,使得用戶對單個對象和組合對象的使用具有一致性灸撰。)
[圖片上傳失敗...(image-812154-1530774668239)]
● Component抽象構件角色
定義參加組合對象的共有方法和屬性谒府,可以定義一些默認的行為或屬性,比如我們例子中的getInfo就封裝到了抽象類中浮毯。
● Leaf葉子構件
葉子對象完疫,其下再也沒有其他的分支,也就是遍歷的最小單位债蓝。
● Composite樹枝構件
樹枝對象壳鹤,它的作用是組合樹枝節(jié)點和葉子節(jié)點形成一個樹形結構。
樹枝構件的通用代碼:
[](javascript:void(0); "復制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">public class Composite extends Component { //構件容器
private ArrayList<Component> componentArrayList = new ArrayList<Component>(); //增加一個葉子構件或樹枝構件
public void add(Component component){ this.componentArrayList.add(component);
} //刪除一個葉子構件或樹枝構件
public void remove(Component component){ this.componentArrayList.remove(component);
} //獲得分支下的所有葉子構件和樹枝構件
public ArrayList<Component> getChildren(){ return this.componentArrayList;
}
}</pre>
](javascript:void(0); "復制代碼")
使用場景:
● 維護和展示部分-整體關系的場景饰迹,如樹形菜單芳誓、文件和文件夾管理。
● 從一個整體中能夠獨立出部分模塊或功能的場景啊鸭。
注意:
只要是樹形結構锹淌,就考慮使用組合模式。
16.觀察者模式(Observer Pattern)
定義:Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically.(定義對象間一種一對多的依賴關系赠制,使得每當一個對象改變狀態(tài)赂摆,則所有依賴于它的對象都會得到通知并被自動更新。)
[圖片上傳失敗...(image-5f1e74-1530774668239)]
● Subject被觀察者
定義被觀察者必須實現的職責钟些,它必須能夠動態(tài)地增加烟号、取消觀察者。它一般是抽象類或者是實現類政恍,僅僅完成作為被觀察者必須實現的職責:管理觀察者并通知觀察者汪拥。
● Observer觀察者
觀察者接收到消息后,即進行update(更新方法)操作篙耗,對接收到的信息進行處理迫筑。
● ConcreteSubject具體的被觀察者
定義被觀察者自己的業(yè)務邏輯宪赶,同時定義對哪些事件進行通知。
● ConcreteObserver具體的觀察者
每個觀察在接收到消息后的處理反應是不同铣焊,各個觀察者有自己的處理邏輯逊朽。
被觀察者通用代碼:
[](javascript:void(0); "復制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">public abstract class Subject { //定義一個觀察者數組
private Vector<Observer> obsVector = new Vector<Observer>(); //增加一個觀察者
public void addObserver(Observer o){ this.obsVector.add(o);
} //刪除一個觀察者
public void delObserver(Observer o){ this.obsVector.remove(o);
} //通知所有觀察者
public void notifyObservers(){ for(Observer o:this.obsVector){
o.update();
}
}
}</pre>
](javascript:void(0); "復制代碼")
使用場景:
● 關聯行為場景。需要注意的是曲伊,關聯行為是可拆分的叽讳,而不是“組合”關系。
● 事件多級觸發(fā)場景坟募。
● 跨系統(tǒng)的消息交換場景岛蚤,如消息隊列的處理機制。
注意:
● 廣播鏈的問題
在一個觀察者模式中最多出現一個對象既是觀察者也是被觀察者懈糯,也就是說消息最多轉發(fā)一次(傳遞兩次)涤妒。
● 異步處理問題
觀察者比較多,而且處理時間比較長赚哗,采用異步處理來考慮線程安全和隊列的問題她紫。
17.門面模式(Facade Pattern)
定義:Provide a unified interface to a set of interfaces in a subsystem.Facade defines a higher-level interface that makes the subsystem easier to use.(要求一個子系統(tǒng)的外部與其內部的通信必須通過一個統(tǒng)一的對象進行。門面模式提供一個高層次的接口屿储,使得子系統(tǒng)更易于使用贿讹。)
[圖片上傳失敗...(image-211079-1530774668238)]
● Facade門面角色 客戶端可以調用這個角色的方法。此角色知曉子系統(tǒng)的所有功能和責任够掠。一般情況下民褂,本角色會將所有從客戶端發(fā)來的請求委派到相應的子系統(tǒng)去,也就說該角色沒有實際的業(yè)務邏輯疯潭,只是一個委托類赊堪。 ● subsystem子系統(tǒng)角色 可以同時有一個或者多個子系統(tǒng)。每一個子系統(tǒng)都不是一個單獨的類竖哩,而是一個類的集合哭廉。子系統(tǒng)并不知道門面的存在。對于子系統(tǒng)而言相叁,門面僅僅是另外一個客戶端而已遵绰。
使用場景:
● 為一個復雜的模塊或子系統(tǒng)提供一個供外界訪問的接口
● 子系統(tǒng)相對獨立——外界對子系統(tǒng)的訪問只要黑箱操作即可
● 預防低水平人員帶來的風險擴散
注意:
●一個子系統(tǒng)可以有多個門面
●門面不參與子系統(tǒng)內的業(yè)務邏輯
18.備忘錄模式(Memento Pattern)
定義:Without violating encapsulation,capture and externalize an object's internal state so that the object can be restored to this state later.(在不破壞封裝性的前提下,捕獲一個對象的內部狀態(tài)钝荡,并在該對象之外保存這個狀態(tài)。這樣以后就可將該對象恢復到原先保存的狀態(tài)舶衬。)
[圖片上傳失敗...(image-786417-1530774668236)]
● Originator發(fā)起人角色
記錄當前時刻的內部狀態(tài)埠通,負責定義哪些屬于備份范圍的狀態(tài),負責創(chuàng)建和恢復備忘錄數據逛犹。
● Memento備忘錄角色(簡單的javabean)
負責存儲Originator發(fā)起人對象的內部狀態(tài)端辱,在需要的時候提供發(fā)起人需要的內部狀態(tài)梁剔。
● Caretaker備忘錄管理員角色(簡單的javabean)
對備忘錄進行管理、保存和提供備忘錄舞蔽。
使用場景:
● 需要保存和恢復數據的相關狀態(tài)場景荣病。
● 提供一個可回滾(rollback)的操作。
● 需要監(jiān)控的副本場景中渗柿。
● 數據庫連接的事務管理就是用的備忘錄模式个盆。
注意:
●備忘錄的生命期
●備忘錄的性能
不要在頻繁建立備份的場景中使用備忘錄模式(比如一個for循環(huán)中)。
clone方式備忘錄:
[圖片上傳失敗...(image-bf291b-1530774668236)]
● 發(fā)起人角色融合了發(fā)起人角色和備忘錄角色朵栖,具有雙重功效
多狀態(tài)的備忘錄模式
[圖片上傳失敗...(image-279e4c-1530774668235)]
● 增加了一個BeanUtils類颊亮,其中backupProp是把發(fā)起人的所有屬性值轉換到HashMap中,方便備忘錄角色存儲陨溅。restoreProp方法則是把HashMap中的值返回到發(fā)起人角色中终惑。
BeanUtil工具類代碼:
[](javascript:void(0); "復制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">public class BeanUtils { //把bean的所有屬性及數值放入到Hashmap中
public static HashMap<String,Object> backupProp(Object bean){
HashMap<String,Object> result = new HashMap<String,Object>(); try { //獲得Bean描述
BeanInfo beanInfo=Introspector.getBeanInfo(bean.getClass()); //獲得屬性描述
PropertyDescriptor[] descriptors=beanInfo.getPropertyDescriptors(); //遍歷所有屬性
for(PropertyDescriptor des:descriptors){ //屬性名稱
String fieldName = des.getName(); //讀取屬性的方法
Method getter = des.getReadMethod(); //讀取屬性值
Object fieldValue=getter.invoke(bean,new Object[]{}); if(!fieldName.equalsIgnoreCase("class")){
result.put(fieldName, fieldValue);
}
}
} catch (Exception e) { //異常處理
} return result;
} //把HashMap的值返回到bean中
public static void restoreProp(Object bean,HashMap<String,Object> propMap){ try { //獲得Bean描述
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); //獲得屬性描述
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); //遍歷所有屬性
for(PropertyDescriptor des:descriptors){ //屬性名稱
String fieldName = des.getName(); //如果有這個屬性
if(propMap.containsKey(fieldName)){ //寫屬性的方法
Method setter = des.getWriteMethod();
setter.invoke(bean, new Object[]{propMap.get(fieldName)});
}
}
} catch (Exception e) { //異常處理
System.out.println("shit");
e.printStackTrace();
}
}
}</pre>
](javascript:void(0); "復制代碼")
多備份的備忘錄:略
封裝得更好一點:保證只能對發(fā)起人可讀
[圖片上傳失敗...(image-a30879-1530774668235)]
●建立一個空接口IMemento——什么方法屬性都沒有的接口,然后在發(fā)起人Originator類中建立一個內置類(也叫做類中類)Memento實現IMemento接口门扇,同時也實現自己的業(yè)務邏輯雹有。
19.訪問者模式(Visitor Pattern)
定義:Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates. (封裝一些作用于某種數據結構中的各元素的操作,它可以在不改變數據結構的前提下定義作用于這些元素的新的操作臼寄。)
[圖片上傳失敗...(image-1da31d-1530774668235)]
● Visitor——抽象訪問者
抽象類或者接口霸奕,聲明訪問者可以訪問哪些元素,具體到程序中就是visit方法的參數定義哪些對象是可以被訪問的脯厨。
● ConcreteVisitor——具體訪問者
它影響訪問者訪問到一個類后該怎么干铅祸,要做什么事情。
● Element——抽象元素
接口或者抽象類合武,聲明接受哪一類訪問者訪問临梗,程序上是通過accept方法中的參數來定義的。
● ConcreteElement——具體元素
實現accept方法稼跳,通常是visitor.visit(this)盟庞,基本上都形成了一種模式了。
● ObjectStruture——結構對象
元素產生者汤善,一般容納在多個不同類什猖、不同接口的容器,如List红淡、Set不狮、Map等,在項目中在旱,一般很少抽象出這個角色摇零。
使用場景:
● 一個對象結構包含很多類對象,它們有不同的接口桶蝎,而你想對這些對象實施一些依賴于其具體類的操作驻仅,也就說是用迭代器模式已經不能勝任的情景谅畅。
● 需要對一個對象結構中的對象進行很多不同并且不相關的操作,而你想避免讓這些操作“污染”這些對象的類噪服。
20.狀態(tài)模式(復雜)
定義:Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.(當一個對象內在狀態(tài)改變時允許其改變行為毡泻,這個對象看起來像改變了其類。)
[圖片上傳失敗...(image-b4f898-1530774668234)]
● State——抽象狀態(tài)角色
接口或抽象類粘优,負責對象狀態(tài)定義仇味,并且封裝環(huán)境角色以實現狀態(tài)切換。
● ConcreteState——具體狀態(tài)角色
每一個具體狀態(tài)必須完成兩個職責:本狀態(tài)的行為管理以及趨向狀態(tài)處理敬飒,通俗地說邪铲,就是本狀態(tài)下要做的事情,以及本狀態(tài)如何過渡到其他狀態(tài)无拗。
● Context——環(huán)境角色
定義客戶端需要的接口带到,并且負責具體狀態(tài)的切換。
使用場景:
● 行為隨狀態(tài)改變而改變的場景
這也是狀態(tài)模式的根本出發(fā)點英染,例如權限設計揽惹,人員的狀態(tài)不同即使執(zhí)行相同的行為結果也會不同,在這種情況下需要考慮使用狀態(tài)模式四康。
● 條件搪搏、分支判斷語句的替代者
注意:
狀態(tài)模式適用于當某個對象在它的狀態(tài)發(fā)生改變時,它的行為也隨著發(fā)生比較大的變化闪金,也就是說在行為受狀態(tài)約束的情況下可以使用狀態(tài)模式疯溺,而且使用時對象的狀態(tài)最好不要超過5個。
21.解釋器模式(Interpreter Pattern)(少用)
定義:Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.(給定一門語言哎垦,定義它的文法的一種表示囱嫩,并定義一個解釋器,該解釋器使用該表示來解釋語言中的句子漏设。)
[圖片上傳失敗...(image-8b4810-1530774668234)]
● AbstractExpression——抽象解釋器
具體的解釋任務由各個實現類完成墨闲,具體的解釋器分別由TerminalExpression和Non-terminalExpression完成。
● TerminalExpression——終結符表達式
實現與文法中的元素相關聯的解釋操作郑口,通常一個解釋器模式中只有一個終結符表達式鸳碧,但有多個實例,對應不同的終結符犬性。具體到我們例子就是VarExpression類瞻离,表達式中的每個終結符都在棧中產生了一個VarExpression對象。
● NonterminalExpression——非終結符表達式
文法中的每條規(guī)則對應于一個非終結表達式乒裆,具體到我們的例子就是加減法規(guī)則分別對應到AddExpression和SubExpression兩個類套利。非終結符表達式根據邏輯的復雜程度而增加,原則上每個文法規(guī)則都對應一個非終結符表達式。
● Context——環(huán)境角色
具體到我們的例子中是采用HashMap代替日裙。
使用場景:
● 重復發(fā)生的問題可以使用解釋器模式
● 一個簡單語法需要解釋的場景
注意:
盡量不要在重要的模塊中使用解釋器模式,否則維護會是一個很大的問題惰蜜。在項目中可以使用shell昂拂、JRuby、Groovy等腳本語言來代替解釋器模式抛猖,彌補Java編譯型語言的不足格侯。
22.享元模式(Flyweight Pattern)
定義:Use sharing to support large numbers of fine-grained objects efficiently.(使用共享對象可有效地支持大量的細粒度的對象。)
對象的信息分為兩個部分:內部狀態(tài)(intrinsic)與外部狀態(tài)(extrinsic)财著。
● 內部狀態(tài)
內部狀態(tài)是對象可共享出來的信息联四,存儲在享元對象內部并且不會隨環(huán)境改變而改變。
● 外部狀態(tài)
外部狀態(tài)是對象得以依賴的一個標記撑教,是隨環(huán)境改變而改變的朝墩、不可以共享的狀態(tài)。
[圖片上傳失敗...(image-34bfa5-1530774668234)]
● Flyweight——抽象享元角色
它簡單地說就是一個產品的抽象類伟姐,同時定義出對象的外部狀態(tài)和內部狀態(tài)的接口或實現收苏。
● ConcreteFlyweight——具體享元角色
具體的一個產品類,實現抽象角色定義的業(yè)務愤兵。該角色中需要注意的是內部狀態(tài)處理應該與環(huán)境無關鹿霸,不應該出現一個操作改變了內部狀態(tài),同時修改了外部狀態(tài)秆乳,這是絕對不允許的懦鼠。
● unsharedConcreteFlyweight——不可共享的享元角色
不存在外部狀態(tài)或者安全要求(如線程安全)不能夠使用共享技術的對象,該對象一般不會出現在享元工廠中屹堰。
● FlyweightFactory——享元工廠
職責非常簡單肛冶,就是構造一個池容器,同時提供從池中獲得對象的方法双藕。
享元工廠的代碼:
[](javascript:void(0); "復制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">public class FlyweightFactory { //定義一個池容器
private static HashMap<String,Flyweight> pool= new HashMap<String,Flyweight>(); //享元工廠
public static Flyweight getFlyweight(String Extrinsic){ //需要返回的對象
Flyweight flyweight = null; //在池中沒有該對象
if(pool.containsKey(Extrinsic)){
flyweight = pool.get(Extrinsic);
}else{ //根據外部狀態(tài)創(chuàng)建享元對象
flyweight = new ConcreteFlyweight1(Extrinsic); //放置到池中
pool.put(Extrinsic, flyweight);
} return flyweight;
}
}</pre>
](javascript:void(0); "復制代碼")
使用場景:
● 系統(tǒng)中存在大量的相似對象淑趾。
● 細粒度的對象都具備較接近的外部狀態(tài),而且內部狀態(tài)與環(huán)境無關忧陪,也就是說對象沒有特定身份扣泊。
● 需要緩沖池的場景。
注意:
● 享元模式是線程不安全的嘶摊,只有依靠經驗延蟹,在需要的地方考慮一下線程安全,在大部分場景下不用考慮叶堆。對象池中的享元對象盡量多阱飘,多到足夠滿足為止。
● 性能安全:外部狀態(tài)最好以java的基本類型作為標志,如String沥匈,int蔗喂,可以提高效率。
23.橋梁模式(Bridge Pattern)
定義:Decouple an abstraction from its implementation so that the two can vary independently.(將抽象和實現解耦高帖,使得兩者可以獨立地變化缰儿。)
[圖片上傳失敗...(image-e7fbad-1530774668239)]
● Abstraction——抽象化角色
它的主要職責是定義出該角色的行為,同時保存一個對實現化角色的引用散址,該角色一般是抽象類乖阵。
● Implementor——實現化角色
它是接口或者抽象類,定義角色必需的行為和屬性预麸。
● RefinedAbstraction——修正抽象化角色
它引用實現化角色對抽象化角色進行修正瞪浸。
● ConcreteImplementor——具體實現化角色
它實現接口或抽象類定義的方法和屬性。
使用場景:
● 不希望或不適用使用繼承的場景
● 接口或抽象類不穩(wěn)定的場景
● 重用性要求較高的場景
注意:
發(fā)現類的繼承有N層時吏祸,可以考慮使用橋梁模式对蒲。橋梁模式主要考慮如何拆分抽象和實現。
設計原則:
●Single Responsibility Principle:單一職責原則
單一職責原則有什么好處:
● 類的復雜性降低贡翘,實現什么職責都有清晰明確的定義齐蔽;
● 可讀性提高,復雜性降低床估,那當然可讀性提高了含滴;
● 可維護性提高,可讀性提高丐巫,那當然更容易維護了谈况;
●變更引起的風險降低,變更是必不可少的递胧,如果接口的單一職責做得好碑韵,一個接口修改只對相應的實現類有影響,對其他的接口無影響缎脾,這對系統(tǒng)的擴展性祝闻、維護性都有非常大的幫助。
ps:接口一定要做到單一職責遗菠,類的設計盡量做到只有一個原因引起變化联喘。
單一職責原則提出了一個編寫程序的標準,用“職責”或“變化原因”來衡量接口或類設計得是否優(yōu)良辙纬,但是“職責”和“變化原因”都是不可度量的豁遭,因項目而異,因環(huán)境而異贺拣。
● Liskov Substitution Principle:里氏替換原則
定義:Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
(所有引用基類的地方必須能透明地使用其子類的對象蓖谢。)
通俗點講捂蕴,只要父類能出現的地方子類就可以出現,而且替換為子類也不會產生任何錯誤或異常闪幽,使用者可能根本就不需要知道是父類還是子類啥辨。但是,反過來就不行了盯腌,有子類出現的地方委可,父類未必就能適應。
定義中包含的四層含義:
1.子類必須完全實現父類的方法
2.子類可以有自己的個性
3.覆蓋或實現父類的方法時輸入參數可以被放大
如果父類的輸入參數類型大于子類的輸入參數類型腊嗡,會出現父類存在的地方,子類未必會存在拾酝,因為一旦把子類作為參數傳入燕少,調用者很可能進入子類的方法范疇。
4. 覆寫或實現父類的方法時輸出結果可以被縮小
父類的一個方法的返回值是一個類型T蒿囤,子類的相同方法(重載或覆寫)的返回值為S客们,那么里氏替換原則就要求S必須小于等于T,也就是說材诽,要么S和T是同一個類型底挫,要么S是T的子類。
● Interface Segregation Principle:接口隔離原則
接口分為兩種:
實例接口(Object Interface):Java中的類也是一種接口
類接口(Class Interface): Java中經常使用Interface關鍵字定義的接口
隔離:建立單一接口脸侥,不要建立臃腫龐大的接口建邓;即接口要盡量細化,同時接口中的方法要盡量少睁枕。
接口隔離原則與單一職責原則的不同:接口隔離原則與單一職責的審視角度是不相同的官边,單一職責要求的是類和接口職責單一,注重的是職責外遇,這是業(yè)務邏輯上的劃分注簿,而接口隔離原則要求接口的方法盡量少。
● Dependence Inversion Principle:依賴倒置原則
原始定義:
①高層模塊不應該依賴低層模塊跳仿,兩者都應該依賴其抽象诡渴;
②抽象不應該依賴細節(jié)(實現類);
③細節(jié)應該依賴抽象菲语。
依賴倒置原則在java語言中的體現:
①模塊間的依賴通過抽象發(fā)生妄辩,實現類之間不發(fā)生直接的依賴關系,其依賴關系是通過接口或抽象類產生的山上;
②接口或抽象類不依賴于實現類恩袱;
③實現類依賴接口或抽象類。
依賴的三種寫法:
①構造函數傳遞依賴對象(構造函數注入)
②Setter方法傳遞依賴對象(setter依賴注入)
③接口聲明依賴對象(接口注入)
使用原則:
依賴倒置原則的本質就是通過抽象(接口或抽象類)使各個類或模塊的實現彼此獨立胶哲,不互相影響畔塔,實現模塊間的松耦合,我們怎么在項目中使用這個規(guī)則呢?只要遵循以下的幾個規(guī)則就可以:
①每個類盡量都有接口或抽象類澈吨,或者抽象類和接口兩者都具備
②變量的表面類型盡量是接口或者是抽象類
③任何類都不應該從具體類派生(只要不超過兩層的繼承是可以忍受的)
④盡量不要復寫基類的方法
⑤結合里氏替換原則使用
●Open Closed Principle:開閉原則
定義:軟件實體應該對擴展開放把敢,對修改關閉。
其含義是說一個軟件實體應該通過擴展來實現變化谅辣,而不是通過修改已有的代碼來實現變化修赞。
軟件實體:項目或軟件產品中按照一定的邏輯規(guī)則劃分的模塊、抽象和類桑阶、方法柏副。
變化的三種類型:
①邏輯變化
只變化一個邏輯,而不涉及其他模塊蚣录,比如原有的一個算法是ab+c割择,現在需要修改為ab*c,可以通過修改原有類中的方法的方式來完成萎河,前提條件是所有依賴或關聯類都按照相同的邏輯處理荔泳。
②子模塊變化
一個模塊變化,會對其他的模塊產生影響虐杯,特別是一個低層次的模塊變化必然引起高層模塊的變化玛歌,因此在通過擴展完成變化時,高層次的模塊修改是必然的擎椰。
③可見視圖變化
可見視圖是提供給客戶使用的界面支子,如JSP程序、Swing界面等达舒,該部分的變化一般會引起連鎖反應(特別是在國內做項目译荞,做歐美的外包項目一般不會影響太大)⌒萜可以通過擴展來完成變化吞歼,這要看我們原有的設計是否靈活。