預(yù)警:本篇文章較長奈惑,建議先mark后看
1.單例模式(Singleton Pattern)
定義:Ensure a class has only one instance, and provide a global point of access
to it.(確保某一個類只有一個實例捡鱼,而且自行實例化并向整個系統(tǒng)提供這個實
例。)
通用代碼:(是線程安全的)
public class Singleton {
private static final Singleton singleton = new Singleton();
//限制產(chǎn)生多個對象
private Singleton(){
}
//通過該方法獲得實例對象
public static Singleton getSingleton(){
return singleton;
}
//類中其他方法坡疼,盡量是 static
public static void doSomething(){
}
}
使用場景:
● 要求生成唯一序列號的環(huán)境箕昭;
● 在整個項目中需要一個共享訪問點或共享數(shù)據(jù)灵妨,例如一個 Web 頁面上的計數(shù)
器,可以不用把每次刷新都記錄到數(shù)據(jù)庫中落竹,使用單例模式保持計數(shù)器的值泌霍,并確
保是線程安全的;
● 創(chuàng)建一個對象需要消耗的資源過多述召,如要訪問 IO 和數(shù)據(jù)庫等資源朱转;
● 需要定義大量的靜態(tài)常量和靜態(tài)方法(如工具類)的環(huán)境,可以采用單例模式
(當(dāng)然积暖,也可以直接聲明為 static 的方式)藤为。
線程不安全實例:
public class Singleton {
private static Singleton singleton = null;
//限制產(chǎn)生多個對象
private Singleton(){
}
//通過該方法獲得實例對象
public static Singleton getSingleton(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
解決辦法:
在 getSingleton 方法前加 synchronized 關(guān)鍵字,也可以在 getSingleton 方法內(nèi)增
加 synchronized 來實現(xiàn)夺刑。最優(yōu)的辦法是如通用代碼那樣寫缅疟。
2.工廠模式
定義:Define an interface for creating an object,but let subclasses decide which
class to instantiate.Factory Method lets a class defer instantiation to subclasses.
(定義一個用于創(chuàng)建對象的接口分别,讓子類決定實例化哪一個類。工廠方法使一個類
的實例化延遲到其子類存淫。)
Product 為抽象產(chǎn)品類負(fù)責(zé)定義產(chǎn)品的共性耘斩,實現(xiàn)對事物最抽象的定義;
Creator 為抽象創(chuàng)建類桅咆,也就是抽象工廠括授,具體如何創(chuàng)建產(chǎn)品類是由具體的實現(xiàn)工
廠 ConcreteCreator 完成的。
具體工廠類代碼:
public class ConcreteCreator extends Creator {
public <T extends Product> T createProduct(Class<T> c){
Product product=null;
try {
product =
(Product)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
//異常處理
}
return (T)product;
}
}
簡單工廠模式:
一個模塊僅需要一個工廠類岩饼,沒有必要把它產(chǎn)生出來荚虚,使用靜態(tài)的方法
多個工廠類:
每個人種(具體的產(chǎn)品類)都對應(yīng)了一個創(chuàng)建者,每個創(chuàng)建者獨立負(fù)責(zé)創(chuàng)建對應(yīng)的
產(chǎn)品對象忌愚,非常符合單一職責(zé)原則
代替單例模式:
單例模式的核心要求就是在內(nèi)存中只有一個對象曲管,通過工廠方法模式也可以只在內(nèi)
存中生產(chǎn)一個對象
延遲初始化:
ProductFactory 負(fù)責(zé)產(chǎn)品類對象的創(chuàng)建工作却邓,并且通過 prMap 變量產(chǎn)生一個緩
存硕糊,對需要再次被重用的對象保留
使用場景:jdbc 連接數(shù)據(jù)庫,硬件訪問腊徙,降低對象的產(chǎn)生和銷毀
3.抽象工廠模式(Abstract Factory
Pattern)
定義:Provide an interface for creating families of related or dependent objects
without specifying their concrete classes.(為創(chuàng)建一組相關(guān)或相互依賴的對象提供
一個接口简十,而且無須指定它們的具體類。)
抽象工廠模式通用類圖:
抽象工廠模式通用源碼類圖:
抽象工廠類代碼:
public abstract class AbstractCreator {
//創(chuàng)建 A 產(chǎn)品家族
public abstract AbstractProductA createProductA();
//創(chuàng)建 B 產(chǎn)品家族
public abstract AbstractProductB createProductB();
}
使用場景:
一個對象族(或是一組沒有任何關(guān)系的對象)都有相同的約束撬腾。
涉及不同操作系統(tǒng)的時候螟蝙,都可以考慮使用抽象工廠模式
4.模板方法模式(Template Method
Pattern)
定義:Define the skeleton of an algorithm in an operation,deferring some steps to
subclasses.Template Method lets subclasses redefine certain steps of an
algorithm without changing the algorithm's structure.(定義一個操作中的算法的框
架,而將一些步驟延遲到子類中民傻。使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義
該算法的某些特定步驟胰默。)
AbstractClass 叫做抽象模板,它的方法分為兩類:
● 基本方法
基本方法也叫做基本操作漓踢,是由子類實現(xiàn)的方法牵署,并且在模板方法被調(diào)用。
● 模板方法
可以有一個或幾個喧半,一般是一個具體方法奴迅,也就是一個框架,實現(xiàn)對基本方法的調(diào)
度挺据,完成固定的邏輯取具。
注意: 為了防止惡意的操作,一般模板方法都加上 final 關(guān)鍵字扁耐,不允許被覆
寫暇检。
具體模板:ConcreteClass1 和 ConcreteClass2 屬于具體模板,實現(xiàn)父類所定義的
一個或多個抽象方法婉称,也就是父類定義的基本方法在子類中得以實現(xiàn)
使用場景:
● 多個子類有公有的方法块仆,并且邏輯基本相同時心墅。
● 重要、復(fù)雜的算法榨乎,可以把核心算法設(shè)計為模板方法怎燥,周邊的相關(guān)細(xì)節(jié)功能則由
各個子類實現(xiàn)。
● 重構(gòu)時蜜暑,模板方法模式是一個經(jīng)常使用的模式铐姚,把相同的代碼抽取到父類中,然
后通過鉤子函數(shù)(見“模板方法模式的擴展”)約束其行為肛捍。
5.建造者模式(Builder Pattern)
定義:Separate the construction of a complex object from its representation so
that the same construction process can create different representations.(將一個
復(fù)雜對象的構(gòu)建與它的表示分離隐绵,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。)
● Product 產(chǎn)品類
通常是實現(xiàn)了模板方法模式拙毫,也就是有模板方法和基本方法依许,例子中的
BenzModel 和 BMWModel 就屬于產(chǎn)品類。
● Builder 抽象建造者
規(guī)范產(chǎn)品的組建缀蹄,一般是由子類實現(xiàn)峭跳。例子中的 CarBuilder 就屬于抽象建造者。
● ConcreteBuilder 具體建造者
實現(xiàn)抽象類定義的所有方法缺前,并且返回一個組建好的對象蛀醉。例子中的 BenzBuilder
和 BMWBuilder 就屬于具體建造者。
● Director 導(dǎo)演類
負(fù)責(zé)安排已有模塊的順序衅码,然后告訴 Builder 開始建造
使用場景:
● 相同的方法拯刁,不同的執(zhí)行順序,產(chǎn)生不同的事件結(jié)果時逝段,可以采用建造者模式垛玻。
● 多個部件或零件,都可以裝配到一個對象中奶躯,但是產(chǎn)生的運行結(jié)果又不相同時帚桩,
則可以使用該模式。
● 產(chǎn)品類非常復(fù)雜巫糙,或者產(chǎn)品類中的調(diào)用順序不同產(chǎn)生了不同的效能朗儒,這個時候使
用建造者模式非常合適。
建造者模式與工廠模式的不同:
建造者模式最主要的功能是基本方法的調(diào)用順序安排参淹,這些基本方法已經(jīng)實現(xiàn)了醉锄,
順序不同產(chǎn)生的對象也不同;
工廠方法則重點是創(chuàng)建浙值,創(chuàng)建零件是它的主要職責(zé)恳不,組裝順序則不是它關(guān)心的。
6.代理模式(Proxy Pattern)
定義:Provide a surrogate or placeholder for another object to control access to it.
(為其他對象提供一種代理以控制對這個對象的訪問开呐。)
● Subject 抽象主題角色
抽象主題類可以是抽象類也可以是接口烟勋,是一個最普通的業(yè)務(wù)類型定義规求,無特殊要
求。
● RealSubject 具體主題角色
也叫做被委托角色卵惦、被代理角色阻肿。它才是冤大頭,是業(yè)務(wù)邏輯的具體執(zhí)行者沮尿。
● Proxy 代理主題角色
也叫做委托類丛塌、代理類。它負(fù)責(zé)對真實角色的應(yīng)用畜疾,把所有抽象主題類定義的方法
限制委托給真實主題角色實現(xiàn)赴邻,并且在真實主題角色處理完畢前后做預(yù)處理和善后
處理工作。
普通代理和強制代理:
普通代理就是我們要知道代理的存在啡捶,也就是類似的 GamePlayerProxy 這個類的
存在姥敛,然后才能訪問;
強制代理則是調(diào)用者直接調(diào)用真實角色瞎暑,而不用關(guān)心代理是否存在彤敛,其代理的產(chǎn)生
是由真實角色決定的。
普通代理:
在該模式下金顿,調(diào)用者只知代理而不用知道真實的角色是誰臊泌,屏蔽了真實角色的變更
對高層模塊的影響鲤桥,真實的主題角色想怎么修改就怎么修改揍拆,對高層次的模塊沒有
任何的影響,只要你實現(xiàn)了接口所對應(yīng)的方法茶凳,該模式非常適合對擴展性要求較高
的場合嫂拴。
強制代理:
強制代理的概念就是要從真實角色查找到代理角色,不允許直接訪問真實角色贮喧。高
層模塊只要調(diào)用 getProxy 就可以訪問真實角色的所有方法筒狠,它根本就不需要產(chǎn)生
一個代理出來,代理的管理已經(jīng)由真實角色自己完成箱沦。
動態(tài)代理:
根據(jù)被代理的接口生成所有的方法辩恼,也就是說給定一個接口,動態(tài)代理會宣稱“我
已經(jīng)實現(xiàn)該接口下的所有方法了”谓形。
兩條獨立發(fā)展的線路灶伊。動態(tài)代理實現(xiàn)代理的職責(zé),業(yè)務(wù)邏輯 Subject 實現(xiàn)相關(guān)的邏
輯功能寒跳,兩者之間沒有必然的相互耦合的關(guān)系聘萨。通知 Advice 從另一個切面切入,
最終在高層模塊也就是 Client 進(jìn)行耦合童太,完成邏輯的封裝任務(wù)米辐。
動態(tài)代理調(diào)用過程示意圖:
動態(tài)代理的意圖:橫切面編程胸完,在不改變我們已有代碼結(jié)構(gòu)的情況下增強或控制對
象的行為。
首要條件:被代理的類必須要實現(xiàn)一個接口翘贮。
7.原型模式(Prototype Pattern)
定義:Specify the kinds of objects to create using a prototypical instance,and
create new objects by copying this prototype.(用原型實例指定創(chuàng)建對象的種類赊窥,
并且通過拷貝這些原型創(chuàng)建新的對象。)
原型模式通用代碼:
public class PrototypeClass implements Cloneable{
//覆寫父類 Object 方法
@Override
public PrototypeClass clone(){
PrototypeClass prototypeClass = null;
try {
prototypeClass = (PrototypeClass)super.clone();
} catch (CloneNotSupportedException e) {
//異常處理
}
return prototypeClass;
}
}
原型模式實際上就是實現(xiàn) Cloneable 接口狸页,重寫 clone()方法誓琼。
使用原型模式的優(yōu)點:
● 性能優(yōu)良
原型模式是在內(nèi)存二進(jìn)制流的拷貝,要比直接 new 一個對象性能好很多肴捉,特別是
要在一個循環(huán)體內(nèi)產(chǎn)生大量的對象時腹侣,原型模式可以更好地體現(xiàn)其優(yōu)點。
● 逃避構(gòu)造函數(shù)的約束
這既是它的優(yōu)點也是缺點齿穗,直接在內(nèi)存中拷貝傲隶,構(gòu)造函數(shù)是不會執(zhí)行的(參見
13.4 節(jié))。
使用場景:
● 資源優(yōu)化場景
類初始化需要消化非常多的資源窃页,這個資源包括數(shù)據(jù)跺株、硬件資源等。
● 性能和安全要求的場景
通過 new 產(chǎn)生一個對象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問權(quán)限脖卖,則可以使用原型模
式乒省。
● 一個對象多個修改者的場景
一個對象需要提供給其他對象訪問,而且各個調(diào)用者可能都需要修改其值時畦木,可以
考慮使用原型模式拷貝多個對象供調(diào)用者使用袖扛。
淺拷貝和深拷貝:
淺拷貝:Object 類提供的方法 clone 只是拷貝本對象,其對象內(nèi)部的數(shù)組十籍、引用
對象等都不拷貝蛆封,還是指向原生對象的內(nèi)部元素地址,這種拷貝就叫做淺拷貝勾栗,其
他的原始類型比如 int惨篱、long、char围俘、string(當(dāng)做是原始類型)等都會被拷貝砸讳。
注意: 使用原型模式時,引用的成員變量必須滿足兩個條件才不會被拷貝:一是
類的成員變量界牡,而不是方法內(nèi)變量簿寂;二是必須是一個可變的引用對象,而不是一個
原始類型或不可變對象欢揖。
深拷貝:對私有的類變量進(jìn)行獨立的拷貝
如:thing.arrayList = (ArrayList<String>)this.arrayList.clone();
8.中介者模式
定義:Define an object that encapsulates how a set of objects interact.Mediator
promotes loose coupling by keeping objects from referring to each other
explicitly,and it lets you vary their interaction independently.(用一個中介對象封裝
一系列的對象交互陶耍,中介者使各對象不需要顯示地相互作用,從而使其耦合松散她混,
而且可以獨立地改變它們之間的交互烈钞。)
● Mediator 抽象中介者角色
抽象中介者角色定義統(tǒng)一的接口泊碑,用于各同事角色之間的通信。
● Concrete Mediator 具體中介者角色
具體中介者角色通過協(xié)調(diào)各同事角色實現(xiàn)協(xié)作行為毯欣,因此它必須依賴于各個同事角
色馒过。
● Colleague 同事角色
每一個同事角色都知道中介者角色,而且與其他的同事角色通信的時候酗钞,一定要通
過中介者角色協(xié)作腹忽。每個同事類的行為分為兩種:一種是同事本身的行為,比如改
變對象本身的狀態(tài)砚作,處理自己的行為等窘奏,這種行為叫做自發(fā)行為(SelfMethod),與其他的同事類或中介者沒有任何的依賴葫录;第二種是必須依賴中介者
才能完成的行為着裹,叫做依賴方法(Dep-Method)。
通用抽象中介者代碼:
public abstract class Mediator {
//定義同事類
protected ConcreteColleague1 c1;
protected ConcreteColleague2 c2;
//通過 getter/setter 方法把同事類注入進(jìn)來
public ConcreteColleague1 getC1() {
return c1;
}
public void setC1(ConcreteColleague1 c1) {
this.c1 = c1;
}
public ConcreteColleague2 getC2() {
return c2;
}
public void setC2(ConcreteColleague2 c2) {
this.c2 = c2;
}
//中介者模式的業(yè)務(wù)邏輯
public abstract void doSomething1();
public abstract void doSomething2();
}
ps:使用同事類注入而不使用抽象注入的原因是因為抽象類中不具有每個同事類
必須要完成的方法米同。即每個同事類中的方法各不相同骇扇。
問:為什么同事類要使用構(gòu)造函數(shù)注入中介者,而中介者使用 getter/setter 方式注
入同事類呢面粮?
這是因為同事類必須有中介者少孝,而中介者卻可以只有部分同事類。
使用場景:
中介者模式適用于多個對象之間緊密耦合的情況熬苍,緊密耦合的標(biāo)準(zhǔn)是:在類圖中出
現(xiàn)了蜘蛛網(wǎng)狀結(jié)構(gòu)稍走,即每個類都與其他的類有直接的聯(lián)系。
9.命令模式
定義:Encapsulate a request as an object,thereby letting you parameterize clients
with different requests,queue or log requests,and support undoable operations.
(將一個請求封裝成一個對象冷溃,從而讓你使用不同的請求把客戶端參數(shù)化钱磅,對請求
排隊或者記錄請求日志,可以提供命令的撤銷和恢復(fù)功能似枕。)
● Receive 接收者角色
該角色就是干活的角色,命令傳遞到這里是應(yīng)該被執(zhí)行的年柠,具體到我們上面的例子
中就是 Group 的三個實現(xiàn)類(需求組凿歼,美工組,代碼組)冗恨。
● Command 命令角色
需要執(zhí)行的所有命令都在這里聲明答憔。
● Invoker 調(diào)用者角色
接收到命令,并執(zhí)行命令掀抹。在例子中虐拓,我(項目經(jīng)理)就是這個角色。
使用場景:
認(rèn)為是命令的地方就可以采用命令模式傲武,例如蓉驹,在 GUI 開發(fā)中城榛,一個按鈕的點擊
是一個命令,可以采用命令模式态兴;模擬 DOS 命令的時候狠持,當(dāng)然也要采用命令模
式;觸發(fā)-反饋機制的處理等瞻润。
10.責(zé)任鏈模式
定義:Avoid coupling the sender of a request to its receiver by giving more than
one object a chance to handle the request.Chain the receiving objects and pass
the request along the chain until an object handles it.(使多個對象都有機會處理請
求喘垂,從而避免了請求的發(fā)送者和接受者之間的耦合關(guān)系。將這些對象連成一條鏈绍撞,
并沿著這條鏈傳遞該請求正勒,直到有對象處理它為止。)
抽象處理者的代碼:
public abstract class Handler {
private Handler nextHandler;
//每個處理者都必須對請求做出處理
public final Response handleMessage(Request request){
Response response = null;
//判斷是否是自己的處理級別
if(this.getHandlerLevel().equals(request.getRequestLevel())){
response = this.echo(request);
}else{ //不屬于自己的處理級別
//判斷是否有下一個處理者
if(this.nextHandler != null){
response =
this.nextHandler.handleMessage(request);
}else{
//沒有適當(dāng)?shù)奶幚碚呱迪常瑯I(yè)務(wù)自行處理
}
}
return response;
}
//設(shè)置下一個處理者是誰
public void setNext(Handler _handler){
this.nextHandler = _handler;
}
//每個處理者都有一個處理級別
protected abstract Level getHandlerLevel();
//每個處理者都必須實現(xiàn)處理任務(wù)
protected abstract Response echo(Request request);
}
抽象的處理者實現(xiàn)三個職責(zé):
一是定義一個請求的處理方法 handleMessage昭齐,唯一對外開放的方法;
二是定義一個鏈的編排方法 setNext矾柜,設(shè)置下一個處理者阱驾;
三是定義了具體的請求者必須實現(xiàn)的兩個方法:定義自己能夠處理的級別
getHandlerLevel 和具體的處理任務(wù) echo。
注意事項:
鏈中節(jié)點數(shù)量需要控制怪蔑,避免出現(xiàn)超長鏈的情況里覆,一般的做法是在 Handler 中設(shè)置
一個最大節(jié)點數(shù)量,在 setNext 方法中判斷是否已經(jīng)是超過其閾值缆瓣,超過則不允許
該鏈建立喧枷,避免無意識地破壞系統(tǒng)性能。
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)地給一個對象添加一些額外的職責(zé)弓坞。就增加功能來
說隧甚,裝飾模式相比生成子類更為靈活。)
● Component 抽象構(gòu)件
Component 是一個接口或者是抽象類渡冻,就是定義我們最核心的對象戚扳,也就是最原
始的對象,如上面的成績單族吻。
注意:在裝飾模式中帽借,必然有一個最基本、最核心超歌、最原始的接口或抽象類充當(dāng)
Component 抽象構(gòu)件砍艾。
● ConcreteComponent 具體構(gòu)件
ConcreteComponent 是最核心、最原始巍举、最基本的接口或抽象類的實現(xiàn)脆荷,你要裝
飾的就是它。
● Decorator 裝飾角色
一般是一個抽象類,做什么用呢蜓谋?實現(xiàn)接口或者抽象方法梦皮,它里面可不一定有抽象
的方法呀,在它的屬性里必然有一個 private 變量指向 Component 抽象構(gòu)件孤澎。
● 具體裝飾角色
ConcreteDecoratorA 和 ConcreteDecoratorB 是兩個具體的裝飾類届氢,你要把你最核
心的、最原始的覆旭、最基本的東西裝飾成其他東西退子,上面的例子就是把一個比較平庸
的成績單裝飾成家長認(rèn)可的成績單。
使用場景:
● 需要擴展一個類的功能型将,或給一個類增加附加功能寂祥。
● 需要動態(tài)地給一個對象增加功能,這些功能可以再動態(tài)地撤銷七兜。
● 需要為一批的兄弟類進(jìn)行改裝或加裝功能丸凭,當(dāng)然是首選裝飾模式。
12.策略模式(Strategy Pattern)
定義:Define a family of algorithms,encapsulate each one,and make them
interchangeable.(定義一組算法腕铸,將每個算法都封裝起來惜犀,并且使它們之間可以
互換。)
● Context 封裝角色
它也叫做上下文角色狠裹,起承上啟下封裝作用虽界,屏蔽高層模塊對策略、算法的直接訪
問涛菠,封裝可能存在的變化莉御。
● Strategy 抽象策略角色
策略、算法家族的抽象俗冻,通常為接口礁叔,定義每個策略或算法必須具有的方法和屬
性。各位看官可能要問了迄薄,類圖中的 AlgorithmInterface 是什么意思琅关,嘿嘿,
algorithm 是“運算法則”的意思噪奄,結(jié)合起來意思就明白了吧死姚。
● ConcreteStrategy 具體策略角色(多個)
實現(xiàn)抽象策略中的操作,該類含有具體的算法勤篮。
使用場景:
● 多個類只有在算法或行為上稍有不同的場景。
● 算法需要自由切換的場景色罚。
● 需要屏蔽算法規(guī)則的場景碰缔。
注意事項:具體策略數(shù)量超過 4 個,則需要考慮使用混合模式
策略模式擴展:策略枚舉
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;
}
//聲明一個抽象函數(shù)
public abstract int exec(int a,int b);
}
定義:
● 它是一個枚舉戳护。
● 它是一個濃縮了的策略模式的枚舉金抡。
注意:
受枚舉類型的限制瀑焦,每個枚舉項都是 public、final梗肝、static 的榛瓮,擴展性受到了一定
的約束,因此在系統(tǒng)開發(fā)中巫击,策略枚舉一般擔(dān)當(dāng)不經(jīng)常發(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.(將一個類的接口變換成客戶端所期待的另一種接口粹懒,從
而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。)
類適配器:
● Target 目標(biāo)角色
該角色定義把其他類轉(zhuǎn)換為何種接口顷级,也就是我們的期望接口凫乖,例子中的
IUserInfo 接口就是目標(biāo)角色。
● Adaptee 源角色
你想把誰轉(zhuǎn)換成目標(biāo)角色弓颈,這個“誰”就是源角色帽芽,它是已經(jīng)存在的、運行良好的類
或?qū)ο笙杓剑?jīng)過適配器角色的包裝导街,它會成為一個嶄新、靚麗的角色橘蜜。
● Adapter 適配器角色
適配器模式的核心角色菊匿,其他兩個角色都是已經(jīng)存在的角色,而適配器角色是需要
新建立的计福,它的職責(zé)非常簡單:把源角色轉(zhuǎn)換為目標(biāo)角色跌捆,怎么轉(zhuǎn)換?通過繼承或
是類關(guān)聯(lián)的方式象颖。
使用場景:
你有動機修改一個已經(jīng)投產(chǎn)中的接口時佩厚,適配器模式可能是最適合你的模式。比如
系統(tǒng)擴展了说订,需要使用一個已有或新建立的類抄瓦,但這個類又不符合系統(tǒng)的接口,怎
么辦陶冷?使用適配器模式钙姊,這也是我們例子中提到的黎棠。
注意事項:
詳細(xì)設(shè)計階段不要考慮使用適配器模式边灭,使用主要場景為擴展應(yīng)用中。
對象適配器:
對象適配器和類適配器的區(qū)別:
類適配器是類間繼承荒吏,對象適配器是對象的合成關(guān)系,也可以說是類的關(guān)聯(lián)關(guān)系膊毁,
這是兩者的根本區(qū)別胀莹。(實際項目中對象適配器使用到的場景相對比較多)。
14.迭代器模式(Iterator Pattern)
定義:Provide a way to access the elements of an aggregate object sequentially
without exposing its underlying representation.(它提供一種方法訪問一個容器對
象中各個元素婚温,而又不需暴露該對象的內(nèi)部細(xì)節(jié)描焰。)
● Iterator 抽象迭代器
抽象迭代器負(fù)責(zé)定義訪問和遍歷元素的接口,而且基本上是有固定的 3 個方法:
first()獲得第一個元素栅螟,next()訪問下一個元素荆秦,isDone()是否已經(jīng)訪問到底部
(Java 叫做 hasNext()方法)。
● ConcreteIterator 具體迭代器
具體迭代器角色要實現(xiàn)迭代器接口嵌巷,完成容器元素的遍歷萄凤。
● Aggregate 抽象容器
容器角色負(fù)責(zé)提供創(chuàng)建具體迭代器角色的接口,必然提供一個類似 createIterator()
這樣的方法搪哪,在 Java 中一般是 iterator()方法靡努。
● Concrete Aggregate 具體容器
具體容器實現(xiàn)容器接口定義的方法,創(chuàng)建出容納迭代器的對象晓折。
ps:迭代器模式已經(jīng)被淘汰惑朦,java 中已經(jīng)把迭代器運用到各個聚集類
(collection)中了,使用 java 自帶的迭代器就已經(jīng)滿足我們的需求了漓概。
15.組合模式((Composite Pattern))
定義:Compose objects into tree structures to represent part-whole
hierarchies.Composite lets clients treat individual objects and compositions of
objects uniformly.(將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)漾月,使得用
戶對單個對象和組合對象的使用具有一致性。)
● Component 抽象構(gòu)件角色
定義參加組合對象的共有方法和屬性胃珍,可以定義一些默認(rèn)的行為或?qū)傩粤褐祝热缥覀?br>
例子中的 getInfo 就封裝到了抽象類中。
● Leaf 葉子構(gòu)件
葉子對象觅彰,其下再也沒有其他的分支吩蔑,也就是遍歷的最小單位。
● Composite 樹枝構(gòu)件
樹枝對象填抬,它的作用是組合樹枝節(jié)點和葉子節(jié)點形成一個樹形結(jié)構(gòu)烛芬。
樹枝構(gòu)件的通用代碼:
public class Composite extends Component {
//構(gòu)件容器
private ArrayList<Component> componentArrayList = new
ArrayList<Component>();
//增加一個葉子構(gòu)件或樹枝構(gòu)件
public void add(Component component){
this.componentArrayList.add(component);
}
//刪除一個葉子構(gòu)件或樹枝構(gòu)件
public void remove(Component component){
this.componentArrayList.remove(component);
}
//獲得分支下的所有葉子構(gòu)件和樹枝構(gòu)件
public ArrayList<Component> getChildren(){
return this.componentArrayList;
}
}
使用場景:
● 維護(hù)和展示部分-整體關(guān)系的場景,如樹形菜單飒责、文件和文件夾管理赘娄。
● 從一個整體中能夠獨立出部分模塊或功能的場景。
注意:
只要是樹形結(jié)構(gòu)宏蛉,就考慮使用組合模式遣臼。
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.
(定義對象間一種一對多的依賴關(guān)系,使得每當(dāng)一個對象改變狀態(tài)拾并,則所有依賴于
它的對象都會得到通知并被自動更新暑诸。)
● Subject 被觀察者
定義被觀察者必須實現(xiàn)的職責(zé)蚌讼,它必須能夠動態(tài)地增加辟灰、取消觀察者个榕。它一般是抽
象類或者是實現(xiàn)類,僅僅完成作為被觀察者必須實現(xiàn)的職責(zé):管理觀察者并通知觀
察者芥喇。
● Observer 觀察者
觀察者接收到消息后西采,即進(jìn)行 update(更新方法)操作,對接收到的信息進(jìn)行處
理继控。
● ConcreteSubject 具體的被觀察者
定義被觀察者自己的業(yè)務(wù)邏輯械馆,同時定義對哪些事件進(jìn)行通知。
● ConcreteObserver 具體的觀察者
每個觀察在接收到消息后的處理反應(yīng)是不同武通,各個觀察者有自己的處理邏輯霹崎。
被觀察者通用代碼:
public abstract class Subject {
//定義一個觀察者數(shù)組
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();
}
}
}
使用場景:
● 關(guān)聯(lián)行為場景。需要注意的是冶忱,關(guān)聯(lián)行為是可拆分的尾菇,而不是“組合”關(guān)系。
● 事件多級觸發(fā)場景囚枪。
● 跨系統(tǒng)的消息交換場景派诬,如消息隊列的處理機制。
注意:
● 廣播鏈的問題
在一個觀察者模式中最多出現(xiàn)一個對象既是觀察者也是被觀察者链沼,也就是說消息最
多轉(zhuǎn)發(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)的外部與其內(nèi)部的通信必須通過一個統(tǒng)一的對象進(jìn)行。門面模式提供一個
高層次的接口疾捍,使得子系統(tǒng)更易于使用奈辰。)
● Facade 門面角色
客戶端可以調(diào)用這個角色的方法。此角色知曉子系統(tǒng)的所有功能和責(zé)任拾氓。一般情況
下冯挎,本角色會將所有從客戶端發(fā)來的請求委派到相應(yīng)的子系統(tǒng)去,也就說該角色沒
有實際的業(yè)務(wù)邏輯咙鞍,只是一個委托類房官。
● subsystem 子系統(tǒng)角色
可以同時有一個或者多個子系統(tǒng)。每一個子系統(tǒng)都不是一個單獨的類续滋,而是一個類
的集合翰守。子系統(tǒng)并不知道門面的存在。對于子系統(tǒng)而言疲酌,門面僅僅是另外一個客戶
端而已蜡峰。
使用場景:
● 為一個復(fù)雜的模塊或子系統(tǒng)提供一個供外界訪問的接口
● 子系統(tǒng)相對獨立——外界對子系統(tǒng)的訪問只要黑箱操作即可
● 預(yù)防低水平人員帶來的風(fēng)險擴散
注意:
●一個子系統(tǒng)可以有多個門面
●門面不參與子系統(tǒng)內(nèi)的業(yè)務(wù)邏輯
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.(在不破壞封裝性的前提
下了袁,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)湿颅。這樣以后就可將該
對象恢復(fù)到原先保存的狀態(tài)载绿。)
● Originator 發(fā)起人角色
記錄當(dāng)前時刻的內(nèi)部狀態(tài),負(fù)責(zé)定義哪些屬于備份范圍的狀態(tài)油航,負(fù)責(zé)創(chuàng)建和恢復(fù)備
忘錄數(shù)據(jù)崭庸。
● Memento 備忘錄角色(簡單的 javabean)
負(fù)責(zé)存儲 Originator 發(fā)起人對象的內(nèi)部狀態(tài),在需要的時候提供發(fā)起人需要的內(nèi)部
狀態(tài)谊囚。
● Caretaker 備忘錄管理員角色(簡單的 javabean)
對備忘錄進(jìn)行管理怕享、保存和提供備忘錄。
使用場景:
● 需要保存和恢復(fù)數(shù)據(jù)的相關(guān)狀態(tài)場景镰踏。
● 提供一個可回滾(rollback)的操作函筋。
● 需要監(jiān)控的副本場景中。
● 數(shù)據(jù)庫連接的事務(wù)管理就是用的備忘錄模式奠伪。
注意:
●備忘錄的生命期
●備忘錄的性能
不要在頻繁建立備份的場景中使用備忘錄模式(比如一個 for 循環(huán)中)跌帐。
clone 方式備忘錄:
● 發(fā)起人角色融合了發(fā)起人角色和備忘錄角色,具有雙重功效
多狀態(tài)的備忘錄模式
● 增加了一個 BeanUtils 類芳来,其中 backupProp 是把發(fā)起人的所有屬性值轉(zhuǎn)換到
HashMap 中含末,方便備忘錄角色存儲。restoreProp 方法則是把 HashMap 中的值返
回到發(fā)起人角色中即舌。
BeanUtil 工具類代碼:
public class BeanUtils {
//把 bean 的所有屬性及數(shù)值放入到 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();
}
}
}
多備份的備忘錄:略
封裝得更好一點:保證只能對發(fā)起人可讀
●建立一個空接口 IMemento——什么方法屬性都沒有的接口佣盒,然后在發(fā)起人
Originator 類中建立一個內(nèi)置類(也叫做類中類)Memento 實現(xiàn) IMemento 接口,
同時也實現(xiàn)自己的業(yè)務(wù)邏輯顽聂。
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. (封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中的各元素的
操作肥惭,它可以在不改變數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作。)
● Visitor——抽象訪問者
抽象類或者接口紊搪,聲明訪問者可以訪問哪些元素蜜葱,具體到程序中就是 visit 方法的
參數(shù)定義哪些對象是可以被訪問的。
● ConcreteVisitor——具體訪問者
它影響訪問者訪問到一個類后該怎么干耀石,要做什么事情牵囤。
● Element——抽象元素
接口或者抽象類,聲明接受哪一類訪問者訪問滞伟,程序上是通過 accept 方法中的參
數(shù)來定義的揭鳞。
● ConcreteElement——具體元素
實現(xiàn) accept 方法,通常是 visitor.visit(this)梆奈,基本上都形成了一種模式了野崇。
● ObjectStruture——結(jié)構(gòu)對象
元素產(chǎn)生者,一般容納在多個不同類亩钟、不同接口的容器乓梨,如 List鳖轰、Set、Map 等扶镀,
在項目中蕴侣,一般很少抽象出這個角色。
使用場景:
● 一個對象結(jié)構(gòu)包含很多類對象狈惫,它們有不同的接口睛蛛,而你想對這些對象實施一些
依賴于其具體類的操作,也就說是用迭代器模式已經(jīng)不能勝任的情景胧谈。
● 需要對一個對象結(jié)構(gòu)中的對象進(jìn)行很多不同并且不相關(guān)的操作,而你想避免讓這
些操作“污染”這些對象的類荸频。
20.狀態(tài)模式(復(fù)雜)
定義:Allow an object to alter its behavior when its internal state changes.The
object will appear to change its class.(當(dāng)一個對象內(nèi)在狀態(tài)改變時允許其改變行
為菱肖,這個對象看起來像改變了其類。)
● State——抽象狀態(tài)角色
接口或抽象類旭从,負(fù)責(zé)對象狀態(tài)定義稳强,并且封裝環(huán)境角色以實現(xiàn)狀態(tài)切換。
● ConcreteState——具體狀態(tài)角色
每一個具體狀態(tài)必須完成兩個職責(zé):本狀態(tài)的行為管理以及趨向狀態(tài)處理和悦,通俗地
說退疫,就是本狀態(tài)下要做的事情,以及本狀態(tài)如何過渡到其他狀態(tài)鸽素。
● Context——環(huán)境角色
定義客戶端需要的接口褒繁,并且負(fù)責(zé)具體狀態(tài)的切換。
使用場景:
● 行為隨狀態(tài)改變而改變的場景
這也是狀態(tài)模式的根本出發(fā)點馍忽,例如權(quán)限設(shè)計棒坏,人員的狀態(tài)不同即使執(zhí)行相同的行
為結(jié)果也會不同,在這種情況下需要考慮使用狀態(tài)模式遭笋。
● 條件坝冕、分支判斷語句的替代者
注意:
狀態(tài)模式適用于當(dāng)某個對象在它的狀態(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.
(給定一門語言央串,定義它的文法的一種表示磨澡,并定義一個解釋器,該解釋器使用該
表示來解釋語言中的句子蹋辅。)
● AbstractExpression——抽象解釋器
具體的解釋任務(wù)由各個實現(xiàn)類完成钱贯,具體的解釋器分別由 TerminalExpression 和
Non-terminalExpression 完成。
● TerminalExpression——終結(jié)符表達(dá)式
實現(xiàn)與文法中的元素相關(guān)聯(lián)的解釋操作侦另,通常一個解釋器模式中只有一個終結(jié)符表
達(dá)式秩命,但有多個實例尉共,對應(yīng)不同的終結(jié)符。具體到我們例子就是 VarExpression
類弃锐,表達(dá)式中的每個終結(jié)符都在棧中產(chǎn)生了一個 VarExpression 對象袄友。
● NonterminalExpression——非終結(jié)符表達(dá)式
文法中的每條規(guī)則對應(yīng)于一個非終結(jié)表達(dá)式,具體到我們的例子就是加減法規(guī)則分
別對應(yīng)到 AddExpression 和 SubExpression 兩個類霹菊。非終結(jié)符表達(dá)式根據(jù)邏輯的
復(fù)雜程度而增加剧蚣,原則上每個文法規(guī)則都對應(yīng)一個非終結(jié)符表達(dá)式。
● Context——環(huán)境角色
具體到我們的例子中是采用 HashMap 代替旋廷。
使用場景:
● 重復(fù)發(fā)生的問題可以使用解釋器模式
● 一個簡單語法需要解釋的場景
注意:
盡量不要在重要的模塊中使用解釋器模式鸠按,否則維護(hù)會是一個很大的問題。在項目
中可以使用 shell饶碘、JRuby目尖、Groovy 等腳本語言來代替解釋器模式,彌補 Java 編
譯型語言的不足扎运。
22.享元模式(Flyweight Pattern)
定義:Use sharing to support large numbers of fine-grained objects efficiently.
(使用共享對象可有效地支持大量的細(xì)粒度的對象瑟曲。)
對象的信息分為兩個部分:內(nèi)部狀態(tài)(intrinsic)與外部狀態(tài)(extrinsic)。
● 內(nèi)部狀態(tài)
內(nèi)部狀態(tài)是對象可共享出來的信息豪治,存儲在享元對象內(nèi)部并且不會隨環(huán)境改變而改
變洞拨。
● 外部狀態(tài)
外部狀態(tài)是對象得以依賴的一個標(biāo)記,是隨環(huán)境改變而改變的负拟、不可以共享的狀
態(tài)烦衣。
● Flyweight——抽象享元角色
它簡單地說就是一個產(chǎn)品的抽象類,同時定義出對象的外部狀態(tài)和內(nèi)部狀態(tài)的接口
或?qū)崿F(xiàn)齿椅。
● ConcreteFlyweight——具體享元角色
具體的一個產(chǎn)品類琉挖,實現(xiàn)抽象角色定義的業(yè)務(wù)。該角色中需要注意的是內(nèi)部狀態(tài)處
理應(yīng)該與環(huán)境無關(guān)涣脚,不應(yīng)該出現(xiàn)一個操作改變了內(nèi)部狀態(tài)示辈,同時修改了外部狀態(tài),
這是絕對不允許的遣蚀。
● unsharedConcreteFlyweight——不可共享的享元角色
不存在外部狀態(tài)或者安全要求(如線程安全)不能夠使用共享技術(shù)的對象矾麻,該對象
一般不會出現(xiàn)在享元工廠中。
● FlyweightFactory——享元工廠
職責(zé)非常簡單芭梯,就是構(gòu)造一個池容器险耀,同時提供從池中獲得對象的方法。
享元工廠的代碼:
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{
//根據(jù)外部狀態(tài)創(chuàng)建享元對象
flyweight = new ConcreteFlyweight1(Extrinsic);
//放置到池中
pool.put(Extrinsic, flyweight);
}
return flyweight;
}
}
使用場景:
● 系統(tǒng)中存在大量的相似對象玖喘。
● 細(xì)粒度的對象都具備較接近的外部狀態(tài)甩牺,而且內(nèi)部狀態(tài)與環(huán)境無關(guān),也就是說對
象沒有特定身份累奈。
● 需要緩沖池的場景贬派。
注意:
● 享元模式是線程不安全的急但,只有依靠經(jīng)驗,在需要的地方考慮一下線程安全搞乏,在
大部分場景下不用考慮波桩。對象池中的享元對象盡量多,多到足夠滿足為止请敦。
● 性能安全:外部狀態(tài)最好以 java 的基本類型作為標(biāo)志镐躲,如 String,int侍筛,可以提
高效率萤皂。
23.橋梁模式(Bridge Pattern)
定義:Decouple an abstraction from its implementation so that the two can vary
independently.(將抽象和實現(xiàn)解耦,使得兩者可以獨立地變化勾笆。)
● Abstraction——抽象化角色
它的主要職責(zé)是定義出該角色的行為敌蚜,同時保存一個對實現(xiàn)化角色的引用,該角色
一般是抽象類窝爪。
● Implementor——實現(xiàn)化角色
它是接口或者抽象類,定義角色必需的行為和屬性齐媒。
● RefinedAbstraction——修正抽象化角色
它引用實現(xiàn)化角色對抽象化角色進(jìn)行修正蒲每。
● ConcreteImplementor——具體實現(xiàn)化角色
它實現(xiàn)接口或抽象類定義的方法和屬性。
使用場景:
● 不希望或不適用使用繼承的場景
● 接口或抽象類不穩(wěn)定的場景
● 重用性要求較高的場景
注意:
發(fā)現(xiàn)類的繼承有 N 層時喻括,可以考慮使用橋梁模式邀杏。橋梁模式主要考慮如何拆分抽
象和實現(xiàn)。
設(shè)計原則:
●Single Responsibility Principle:單一職責(zé)原則
單一職責(zé)原則有什么好處:
● 類的復(fù)雜性降低唬血,實現(xiàn)什么職責(zé)都有清晰明確的定義望蜡;
● 可讀性提高,復(fù)雜性降低拷恨,那當(dāng)然可讀性提高了脖律;
● 可維護(hù)性提高,可讀性提高腕侄,那當(dāng)然更容易維護(hù)了小泉;
●變更引起的風(fēng)險降低,變更是必不可少的冕杠,如果接口的單一職責(zé)做得好微姊,一個接
口修改只對相應(yīng)的實現(xiàn)類有影響,對其他的接口無影響分预,這對系統(tǒng)的擴展性兢交、維護(hù)
性都有非常大的幫助。
ps:接口一定要做到單一職責(zé)笼痹,類的設(shè)計盡量做到只有一個原因引起變化配喳。
單一職責(zé)原則提出了一個編寫程序的標(biāo)準(zhǔn)酪穿,用“職責(zé)”或“變化原因”來衡量接口
或類設(shè)計得是否優(yōu)良,但是“職責(zé)”和“變化原因”都是不可度量的界逛,因項目而異昆稿,因
環(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.
(所有引用基類的地方必須能透明地使用其子類的對象息拜。)
通俗點講溉潭,只要父類能出現(xiàn)的地方子類就可以出現(xiàn),而且替換為子類也不會產(chǎn)生任
何錯誤或異常少欺,使用者可能根本就不需要知道是父類還是子類喳瓣。但是,反過來就不
行了赞别,有子類出現(xiàn)的地方畏陕,父類未必就能適應(yīng)。
定義中包含的四層含義:
1.子類必須完全實現(xiàn)父類的方法
2.子類可以有自己的個性
3.覆蓋或?qū)崿F(xiàn)父類的方法時輸入?yún)?shù)可以被放大
如果父類的輸入?yún)?shù)類型大于子類的輸入?yún)?shù)類型仿滔,會出現(xiàn)父類存在的地
方惠毁,子類未必會存在,因為一旦把子類作為參數(shù)傳入崎页,調(diào)用者很可能進(jìn)入子類的方
法范疇鞠绰。
- 覆寫或?qū)崿F(xiàn)父類的方法時輸出結(jié)果可以被縮小
父類的一個方法的返回值是一個類型 T,子類的相同方法(重載或覆寫)的返
回值為 S飒焦,那么里氏替換原則就要求 S 必須小于等于 T蜈膨,也就是說,要么 S 和 T
是同一個類型牺荠,要么 S 是 T 的子類翁巍。
● Interface Segregation Principle:接口隔離原則
接口分為兩種:
實例接口(Object Interface):Java 中的類也是一種接口
類接口(Class Interface): Java 中經(jīng)常使用 Interface 關(guān)鍵字定義的接口
隔離:建立單一接口,不要建立臃腫龐大的接口休雌;即接口要盡量細(xì)化灶壶,同時接口中
的方法要盡量少。
接口隔離原則與單一職責(zé)原則的不同:接口隔離原則與單一職責(zé)的審視角度是不相
同的挑辆,單一職責(zé)要求的是類和接口職責(zé)單一例朱,注重的是職責(zé),這是業(yè)務(wù)邏輯上的劃
分鱼蝉,而接口隔離原則要求接口的方法盡量少洒嗤。
● Dependence Inversion Principle:依賴倒置原則
原始定義:
①高層模塊不應(yīng)該依賴低層模塊,兩者都應(yīng)該依賴其抽象魁亦;
②抽象不應(yīng)該依賴細(xì)節(jié)(實現(xiàn)類)渔隶;
③細(xì)節(jié)應(yīng)該依賴抽象。
依賴倒置原則在 java 語言中的體現(xiàn):
①模塊間的依賴通過抽象發(fā)生,實現(xiàn)類之間不發(fā)生直接的依賴關(guān)系间唉,其依賴關(guān)系是
通過接口或抽象類產(chǎn)生的绞灼;
②接口或抽象類不依賴于實現(xiàn)類;
③實現(xiàn)類依賴接口或抽象類呈野。
依賴的三種寫法:
①構(gòu)造函數(shù)傳遞依賴對象(構(gòu)造函數(shù)注入)
②Setter 方法傳遞依賴對象(setter 依賴注入)
③接口聲明依賴對象(接口注入)
使用原則:
依賴倒置原則的本質(zhì)就是通過抽象(接口或抽象類)使各個類或模塊的實現(xiàn)彼此獨
立低矮,不互相影響,實現(xiàn)模塊間的松耦合被冒,我們怎么在項目中使用這個規(guī)則呢军掂?只要
遵循以下的幾個規(guī)則就可以:
①每個類盡量都有接口或抽象類,或者抽象類和接口兩者都具備
②變量的表面類型盡量是接口或者是抽象類
③任何類都不應(yīng)該從具體類派生(只要不超過兩層的繼承是可以忍受的)
④盡量不要復(fù)寫基類的方法
⑤結(jié)合里氏替換原則使用
●Open Closed Principle:開閉原則
定義:軟件實體應(yīng)該對擴展開放昨悼,對修改關(guān)閉蝗锥。
其含義是說一個軟件實體應(yīng)該通過擴展來實現(xiàn)變化,而不是通過修改已有的代碼來
實現(xiàn)變化率触。
軟件實體:項目或軟件產(chǎn)品中按照一定的邏輯規(guī)則劃分的模塊终议、抽象和類、方法葱蝗。
變化的三種類型:
①邏輯變化
只變化一個邏輯穴张,而不涉及其他模塊,比如原有的一個算法是 ab+c两曼,現(xiàn)在需要修
改為 ab*c陆馁,可以通過修改原有類中的方法的方式來完成,前提條件是所有依賴或
關(guān)聯(lián)類都按照相同的邏輯處理合愈。
②子模塊變化
一個模塊變化,會對其他的模塊產(chǎn)生影響击狮,特別是一個低層次的模塊變化必然引起
高層模塊的變化佛析,因此在通過擴展完成變化時,高層次的模塊修改是必然的彪蓬。
③可見視圖變化
可見視圖是提供給客戶使用的界面寸莫,如 JSP 程序、Swing 界面等档冬,該部分的變化
一般會引起連鎖反應(yīng)(特別是在國內(nèi)做項目膘茎,做歐美的外包項目一般不會影響太
大)】崾模可以通過擴展來完成變化披坏,這要看我們原有的設(shè)計是否靈活。
結(jié)尾
希望讀到這的您能轉(zhuǎn)發(fā)分享和關(guān)注一下我盐数,以后還會更新技術(shù)干貨棒拂,謝謝您的支持!