读书笔记 23种设计模式总结
目錄:
- 1.單例模式(Singleton Pattern)
- 2.工廠模式
- 3.抽象工廠模式(Abstract Factory Pattern)
- 4.模板方法模式(Template Method Pattern)
- 5.建造者模式(Builder Pattern)
- 6.代理模式(Proxy Pattern)
- 7.原型模式(Prototype Pattern)
- 8.中介者模式
- 9.命令模式
- 10.責(zé)任鏈模式
- 11.裝飾模式(Decorator Pattern)
- 12.策略模式(Strategy Pattern)
- 13.適配器模式(Adapter Pattern)
- 14.迭代器模式(Iterator Pattern)
- 16.觀察者模式(Observer Pattern)
- 17.門(mén)面模式(Facade Pattern)
- 19.訪問(wèn)者模式(Visitor Pattern)
- 21.解釋器模式(Interpreter Pattern)(少用)
- 22.享元模式(Flyweight Pattern)
- 23.橋梁模式(Bridge Pattern)
1.單例模式(Singleton Pattern)
定義:Ensure a class has only one instance, and provide a global point of access to it.(確保某一個(gè)類(lèi)只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。)
通用代碼:(是線(xiàn)程安全的)
復(fù)制代碼
public class Singleton {
private static final Singleton singleton = new Singleton();
//限制產(chǎn)生多個(gè)對(duì)象
private Singleton(){
}
//通過(guò)該方法獲得實(shí)例對(duì)象
public static Singleton getSingleton(){
return singleton;
}
//類(lèi)中其他方法,盡量是static
public static void doSomething(){
}
}
使用場(chǎng)景:
● 要求生成唯一序列號(hào)的環(huán)境;
● 在整個(gè)項(xiàng)目中需要一個(gè)共享訪問(wèn)點(diǎn)或共享數(shù)據(jù),例如一個(gè)Web頁(yè)面上的計(jì)數(shù)器,可以不用把每次刷新都記錄到數(shù)據(jù)庫(kù)中,使用單例模式保持計(jì)數(shù)器的值,并確保是線(xiàn)程安全的;
● 創(chuàng)建一個(gè)對(duì)象需要消耗的資源過(guò)多,如要訪問(wèn)IO和數(shù)據(jù)庫(kù)等資源;
● 需要定義大量的靜態(tài)常量和靜態(tài)方法(如工具類(lèi))的環(huán)境,可以采用單例模式(當(dāng)然,也可以直接聲明為static的方式)。
線(xiàn)程不安全實(shí)例:
public class Singleton {
private static Singleton singleton = null;
//限制產(chǎn)生多個(gè)對(duì)象
private Singleton(){
}
//通過(guò)該方法獲得實(shí)例對(duì)象
public static Singleton getSingleton(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
解決辦法:
在getSingleton方法前加synchronized關(guān)鍵字,也可以在getSingleton方法內(nèi)增加synchronized來(lái)實(shí)現(xiàn)。最優(yōu)的辦法是如通用代碼那樣寫(xiě)。
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.(定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類(lèi)決定實(shí)例化哪一個(gè)類(lèi)。工廠方法使一個(gè)類(lèi)的實(shí)例化延遲到其子類(lèi)。)
Product為抽象產(chǎn)品類(lèi)負(fù)責(zé)定義產(chǎn)品的共性,實(shí)現(xiàn)對(duì)事物最抽象的定義;
Creator為抽象創(chuàng)建類(lèi),也就是抽象工廠,具體如何創(chuàng)建產(chǎn)品類(lèi)是由具體的實(shí)現(xiàn)工廠ConcreteCreator完成的。
具體工廠類(lèi)代碼:
public class ConcreteCreator extends Creator {
public T createProduct(Class c){
Product product=null;
try {
product = (Product)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
//異常處理
}
return (T)product;
}
}
簡(jiǎn)單工廠模式:
一個(gè)模塊僅需要一個(gè)工廠類(lèi),沒(méi)有必要把它產(chǎn)生出來(lái),使用靜態(tài)的方法
多個(gè)工廠類(lèi):
每個(gè)人種(具體的產(chǎn)品類(lèi))都對(duì)應(yīng)了一個(gè)創(chuàng)建者,每個(gè)創(chuàng)建者獨(dú)立負(fù)責(zé)創(chuàng)建對(duì)應(yīng)的產(chǎn)品對(duì)象,非常符合單一職責(zé)原則
代替單例模式:
單例模式的核心要求就是在內(nèi)存中只有一個(gè)對(duì)象,通過(guò)工廠方法模式也可以只在內(nèi)存中生產(chǎn)一個(gè)對(duì)象
延遲初始化:
ProductFactory負(fù)責(zé)產(chǎn)品類(lèi)對(duì)象的創(chuàng)建工作,并且通過(guò)prMap變量產(chǎn)生一個(gè)緩存,對(duì)需要再次被重用的對(duì)象保留
使用場(chǎng)景:jdbc連接數(shù)據(jù)庫(kù),硬件訪問(wèn),降低對(duì)象的產(chǎn)生和銷(xiāo)毀
3.抽象工廠模式(Abstract Factory Pattern)
定義:Provide an interface for creating families of related or dependent objects without specifying their concrete classes.(為創(chuàng)建一組相關(guān)或相互依賴(lài)的對(duì)象提供一個(gè)接口,而且無(wú)須指定它們的具體類(lèi)。)
抽象工廠模式通用類(lèi)圖:
抽象工廠模式通用源碼類(lèi)圖:
抽象工廠類(lèi)代碼:
public abstract class AbstractCreator {
//創(chuàng)建A產(chǎn)品家族
public abstract AbstractProductA createProductA();
//創(chuàng)建B產(chǎn)品家族
public abstract AbstractProductB createProductB();
}
使用場(chǎng)景:
一個(gè)對(duì)象族(或是一組沒(méi)有任何關(guān)系的對(duì)象)都有相同的約束。
涉及不同操作系統(tǒng)的時(shí)候,都可以考慮使用抽象工廠模式
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.(定義一個(gè)操作中的算法的框架,而將一些步驟延遲到子類(lèi)中。使得子類(lèi)可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。)
AbstractClass叫做抽象模板,它的方法分為兩類(lèi):
● 基本方法
基本方法也叫做基本操作,是由子類(lèi)實(shí)現(xiàn)的方法,并且在模板方法被調(diào)用。
● 模板方法
可以有一個(gè)或幾個(gè),一般是一個(gè)具體方法,也就是一個(gè)框架,實(shí)現(xiàn)對(duì)基本方法的調(diào)度,完成固定的邏輯。
注意: 為了防止惡意的操作,一般模板方法都加上final關(guān)鍵字,不允許被覆寫(xiě)。
具體模板:ConcreteClass1和ConcreteClass2屬于具體模板,實(shí)現(xiàn)父類(lèi)所定義的一個(gè)或多個(gè)抽象方法,也就是父類(lèi)定義的基本方法在子類(lèi)中得以實(shí)現(xiàn)
使用場(chǎng)景:
● 多個(gè)子類(lèi)有公有的方法,并且邏輯基本相同時(shí)。
● 重要、復(fù)雜的算法,可以把核心算法設(shè)計(jì)為模板方法,周邊的相關(guān)細(xì)節(jié)功能則由各個(gè)子類(lèi)實(shí)現(xiàn)。
● 重構(gòu)時(shí),模板方法模式是一個(gè)經(jīng)常使用的模式,把相同的代碼抽取到父類(lèi)中,然后通過(guò)鉤子函數(shù)(見(jiàn)“模板方法模式的擴(kuò)展”)約束其行為。
5.建造者模式(Builder Pattern)
定義:Separate the construction of a complex object from its representation so that the same construction process can create different representations.(將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。)
● Product產(chǎn)品類(lèi)
通常是實(shí)現(xiàn)了模板方法模式,也就是有模板方法和基本方法,例子中的BenzModel和BMWModel就屬于產(chǎn)品類(lèi)。
● Builder抽象建造者
規(guī)范產(chǎn)品的組建,一般是由子類(lèi)實(shí)現(xiàn)。例子中的CarBuilder就屬于抽象建造者。
● ConcreteBuilder具體建造者
實(shí)現(xiàn)抽象類(lèi)定義的所有方法,并且返回一個(gè)組建好的對(duì)象。例子中的BenzBuilder和BMWBuilder就屬于具體建造者。
● Director導(dǎo)演類(lèi)
負(fù)責(zé)安排已有模塊的順序,然后告訴Builder開(kāi)始建造
使用場(chǎng)景:
● 相同的方法,不同的執(zhí)行順序,產(chǎn)生不同的事件結(jié)果時(shí),可以采用建造者模式。
● 多個(gè)部件或零件,都可以裝配到一個(gè)對(duì)象中,但是產(chǎn)生的運(yùn)行結(jié)果又不相同時(shí),則可以使用該模式。
● 產(chǎn)品類(lèi)非常復(fù)雜,或者產(chǎn)品類(lèi)中的調(diào)用順序不同產(chǎn)生了不同的效能,這個(gè)時(shí)候使用建造者模式非常合適。
建造者模式與工廠模式的不同:
建造者模式最主要的功能是基本方法的調(diào)用順序安排,這些基本方法已經(jīng)實(shí)現(xiàn)了,順序不同產(chǎn)生的對(duì)象也不同;
工廠方法則重點(diǎn)是創(chuàng)建,創(chuàng)建零件是它的主要職責(zé),組裝順序則不是它關(guān)心的。
6.代理模式(Proxy Pattern)
定義:Provide a surrogate or placeholder for another object to control access to it.(為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)。)
● Subject抽象主題角色
抽象主題類(lèi)可以是抽象類(lèi)也可以是接口,是一個(gè)最普通的業(yè)務(wù)類(lèi)型定義,無(wú)特殊要求。
● RealSubject具體主題角色
也叫做被委托角色、被代理角色。它才是冤大頭,是業(yè)務(wù)邏輯的具體執(zhí)行者。
● Proxy代理主題角色
也叫做委托類(lèi)、代理類(lèi)。它負(fù)責(zé)對(duì)真實(shí)角色的應(yīng)用,把所有抽象主題類(lèi)定義的方法限制委托給真實(shí)主題角色實(shí)現(xiàn),并且在真實(shí)主題角色處理完畢前后做預(yù)處理和善后處理工作。
普通代理和強(qiáng)制代理:
普通代理就是我們要知道代理的存在,也就是類(lèi)似的GamePlayerProxy這個(gè)類(lèi)的存在,然后才能訪問(wèn);
強(qiáng)制代理則是調(diào)用者直接調(diào)用真實(shí)角色,而不用關(guān)心代理是否存在,其代理的產(chǎn)生是由真實(shí)角色決定的。
普通代理:
在該模式下,調(diào)用者只知代理而不用知道真實(shí)的角色是誰(shuí),屏蔽了真實(shí)角色的變更對(duì)高層模塊的影響,真實(shí)的主題角色想怎么修改就怎么修改,對(duì)高層次的模塊沒(méi)有任何的影響,只要你實(shí)現(xiàn)了接口所對(duì)應(yīng)的方法,該模式非常適合對(duì)擴(kuò)展性要求較高的場(chǎng)合。
強(qiáng)制代理:
強(qiáng)制代理的概念就是要從真實(shí)角色查找到代理角色,不允許直接訪問(wèn)真實(shí)角色。高層模塊只要調(diào)用getProxy就可以訪問(wèn)真實(shí)角色的所有方法,它根本就不需要產(chǎn)生一個(gè)代理出來(lái),代理的管理已經(jīng)由真實(shí)角色自己完成。
動(dòng)態(tài)代理:
根據(jù)被代理的接口生成所有的方法,也就是說(shuō)給定一個(gè)接口,動(dòng)態(tài)代理會(huì)宣稱(chēng)“我已經(jīng)實(shí)現(xiàn)該接口下的所有方法了”。
兩條獨(dú)立發(fā)展的線(xiàn)路。動(dòng)態(tài)代理實(shí)現(xiàn)代理的職責(zé),業(yè)務(wù)邏輯Subject實(shí)現(xiàn)相關(guān)的邏輯功能,兩者之間沒(méi)有必然的相互耦合的關(guān)系。通知Advice從另一個(gè)切面切入,最終在高層模塊也就是Client進(jìn)行耦合,完成邏輯的封裝任務(wù)。
動(dòng)態(tài)代理調(diào)用過(guò)程示意圖:
動(dòng)態(tài)代理的意圖:橫切面編程,在不改變我們已有代碼結(jié)構(gòu)的情況下增強(qiáng)或控制對(duì)象的行為。
首要條件:被代理的類(lèi)必須要實(shí)現(xiàn)一個(gè)接口。
7.原型模式(Prototype Pattern)
定義:Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.(用原型實(shí)例指定創(chuàng)建對(duì)象的種類(lèi),并且通過(guò)拷貝這些原型創(chuàng)建新的對(duì)象。)
原型模式通用代碼:
public class PrototypeClass implements Cloneable{
//覆寫(xiě)父類(lèi)Object方法
@Override
public PrototypeClass clone(){
PrototypeClass prototypeClass = null;
try {
prototypeClass = (PrototypeClass)super.clone();
} catch (CloneNotSupportedException e) {
//異常處理
}
return prototypeClass;
}
}
原型模式實(shí)際上就是實(shí)現(xiàn)Cloneable接口,重寫(xiě)clone()方法。
使用原型模式的優(yōu)點(diǎn):
● 性能優(yōu)良
原型模式是在內(nèi)存二進(jìn)制流的拷貝,要比直接new一個(gè)對(duì)象性能好很多,特別是要在一個(gè)循環(huán)體內(nèi)產(chǎn)生大量的對(duì)象時(shí),原型模式可以更好地體現(xiàn)其優(yōu)點(diǎn)。
● 逃避構(gòu)造函數(shù)的約束
這既是它的優(yōu)點(diǎn)也是缺點(diǎn),直接在內(nèi)存中拷貝,構(gòu)造函數(shù)是不會(huì)執(zhí)行的(參見(jiàn)13.4節(jié))。
使用場(chǎng)景:
● 資源優(yōu)化場(chǎng)景
類(lèi)初始化需要消化非常多的資源,這個(gè)資源包括數(shù)據(jù)、硬件資源等。
● 性能和安全要求的場(chǎng)景
通過(guò)new產(chǎn)生一個(gè)對(duì)象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問(wèn)權(quán)限,則可以使用原型模式。
● 一個(gè)對(duì)象多個(gè)修改者的場(chǎng)景
一個(gè)對(duì)象需要提供給其他對(duì)象訪問(wèn),而且各個(gè)調(diào)用者可能都需要修改其值時(shí),可以考慮使用原型模式拷貝多個(gè)對(duì)象供調(diào)用者使用。
淺拷貝和深拷貝:
淺拷貝:Object類(lèi)提供的方法clone只是拷貝本對(duì)象,其對(duì)象內(nèi)部的數(shù)組、引用對(duì)象等都不拷貝,還是指向原生對(duì)象的內(nèi)部元素地址,這種拷貝就叫做淺拷貝,其他的原始類(lèi)型比如int、long、char、string(當(dāng)做是原始類(lèi)型)等都會(huì)被拷貝。
注意: 使用原型模式時(shí),引用的成員變量必須滿(mǎn)足兩個(gè)條件才不會(huì)被拷貝:一是類(lèi)的成員變量,而不是方法內(nèi)變量;二是必須是一個(gè)可變的引用對(duì)象,而不是一個(gè)原始類(lèi)型或不可變對(duì)象。
深拷貝:對(duì)私有的類(lèi)變量進(jìn)行獨(dú)立的拷貝
如:thing.arrayList = (ArrayList)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.(用一個(gè)中介對(duì)象封裝一系列的對(duì)象交互,中介者使各對(duì)象不需要顯示地相互作用,從而使其耦合松散,而且可以獨(dú)立地改變它們之間的交互。)
● Mediator 抽象中介者角色
抽象中介者角色定義統(tǒng)一的接口,用于各同事角色之間的通信。
● Concrete Mediator 具體中介者角色
具體中介者角色通過(guò)協(xié)調(diào)各同事角色實(shí)現(xiàn)協(xié)作行為,因此它必須依賴(lài)于各個(gè)同事角色。
● Colleague 同事角色
每一個(gè)同事角色都知道中介者角色,而且與其他的同事角色通信的時(shí)候,一定要通過(guò)中介者角色協(xié)作。每個(gè)同事類(lèi)的行為分為兩種:一種是同事本身的行為,比如改變對(duì)象本身的狀態(tài),處理自己的行為等,這種行為叫做自發(fā)行為(Self-Method),與其他的同事類(lèi)或中介者沒(méi)有任何的依賴(lài);第二種是必須依賴(lài)中介者才能完成的行為,叫做依賴(lài)方法(Dep-Method)。
通用抽象中介者代碼:
public abstract class Mediator {
//定義同事類(lèi)
protected ConcreteColleague1 c1;
protected ConcreteColleague2 c2;
//通過(guò)getter/setter方法把同事類(lèi)注入進(jìn)來(lái)
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:使用同事類(lèi)注入而不使用抽象注入的原因是因?yàn)槌橄箢?lèi)中不具有每個(gè)同事類(lèi)必須要完成的方法。即每個(gè)同事類(lèi)中的方法各不相同。
問(wèn):為什么同事類(lèi)要使用構(gòu)造函數(shù)注入中介者,而中介者使用getter/setter方式注入同事類(lèi)呢?
這是因?yàn)橥骂?lèi)必須有中介者,而中介者卻可以只有部分同事類(lèi)。
使用場(chǎng)景:
中介者模式適用于多個(gè)對(duì)象之間緊密耦合的情況,緊密耦合的標(biāo)準(zhǔn)是:在類(lèi)圖中出現(xiàn)了蜘蛛網(wǎng)狀結(jié)構(gòu),即每個(gè)類(lèi)都與其他的類(lèi)有直接的聯(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.(將一個(gè)請(qǐng)求封裝成一個(gè)對(duì)象,從而讓你使用不同的請(qǐng)求把客戶(hù)端參數(shù)化,對(duì)請(qǐng)求排隊(duì)或者記錄請(qǐng)求日志,可以提供命令的撤銷(xiāo)和恢復(fù)功能。)
● Receive接收者角色
該角色就是干活的角色,命令傳遞到這里是應(yīng)該被執(zhí)行的,具體到我們上面的例子中就是Group的三個(gè)實(shí)現(xiàn)類(lèi)(需求組,美工組,代碼組)。
● Command命令角色
需要執(zhí)行的所有命令都在這里聲明。
● Invoker調(diào)用者角色
接收到命令,并執(zhí)行命令。在例子中,我(項(xiàng)目經(jīng)理)就是這個(gè)角色。
使用場(chǎng)景:
認(rèn)為是命令的地方就可以采用命令模式,例如,在GUI開(kāi)發(fā)中,一個(gè)按鈕的點(diǎn)擊是一個(gè)命令,可以采用命令模式;模擬DOS命令的時(shí)候,當(dāng)然也要采用命令模式;觸發(fā)-反饋機(jī)制的處理等。
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.(使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免了請(qǐng)求的發(fā)送者和接受者之間的耦合關(guān)系。將這些對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有對(duì)象處理它為止。)
抽象處理者的代碼:
public abstract class Handler {
private Handler nextHandler;
//每個(gè)處理者都必須對(duì)請(qǐng)求做出處理
public final Response handleMessage(Request request){
Response response = null;
//判斷是否是自己的處理級(jí)別
if(this.getHandlerLevel().equals(request.getRequestLevel())){
response = this.echo(request);
}else{ //不屬于自己的處理級(jí)別
//判斷是否有下一個(gè)處理者
if(this.nextHandler != null){
response = this.nextHandler.handleMessage(request);
}else{
//沒(méi)有適當(dāng)?shù)奶幚碚?#xff0c;業(yè)務(wù)自行處理
}
}
return response;
}
//設(shè)置下一個(gè)處理者是誰(shuí)
public void setNext(Handler _handler){
this.nextHandler = _handler;
}
//每個(gè)處理者都有一個(gè)處理級(jí)別
protected abstract Level getHandlerLevel();
//每個(gè)處理者都必須實(shí)現(xiàn)處理任務(wù)
protected abstract Response echo(Request request);
}
抽象的處理者實(shí)現(xiàn)三個(gè)職責(zé):
一是定義一個(gè)請(qǐng)求的處理方法handleMessage,唯一對(duì)外開(kāi)放的方法;
二是定義一個(gè)鏈的編排方法setNext,設(shè)置下一個(gè)處理者;
三是定義了具體的請(qǐng)求者必須實(shí)現(xiàn)的兩個(gè)方法:定義自己能夠處理的級(jí)別getHandlerLevel和具體的處理任務(wù)echo。
注意事項(xiàng):
鏈中節(jié)點(diǎn)數(shù)量需要控制,避免出現(xiàn)超長(zhǎng)鏈的情況,一般的做法是在Handler中設(shè)置一個(gè)最大節(jié)點(diǎn)數(shù)量,在setNext方法中判斷是否已經(jīng)是超過(guò)其閾值,超過(guò)則不允許該鏈建立,避免無(wú)意識(shí)地破壞系統(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.(動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來(lái)說(shuō),裝飾模式相比生成子類(lèi)更為靈活。)
● Component抽象構(gòu)件
Component是一個(gè)接口或者是抽象類(lèi),就是定義我們最核心的對(duì)象,也就是最原始的對(duì)象,如上面的成績(jī)單。
注意:在裝飾模式中,必然有一個(gè)最基本、最核心、最原始的接口或抽象類(lèi)充當(dāng)Component抽象構(gòu)件。
● ConcreteComponent 具體構(gòu)件
ConcreteComponent是最核心、最原始、最基本的接口或抽象類(lèi)的實(shí)現(xiàn),你要裝飾的就是它。
● Decorator裝飾角色
一般是一個(gè)抽象類(lèi),做什么用呢?實(shí)現(xiàn)接口或者抽象方法,它里面可不一定有抽象的方法呀,在它的屬性里必然有一個(gè)private變量指向Component抽象構(gòu)件。
● 具體裝飾角色
ConcreteDecoratorA和ConcreteDecoratorB是兩個(gè)具體的裝飾類(lèi),你要把你最核心的、最原始的、最基本的東西裝飾成其他東西,上面的例子就是把一個(gè)比較平庸的成績(jī)單裝飾成家長(zhǎng)認(rèn)可的成績(jī)單。
使用場(chǎng)景:
● 需要擴(kuò)展一個(gè)類(lèi)的功能,或給一個(gè)類(lèi)增加附加功能。
● 需要?jiǎng)討B(tài)地給一個(gè)對(duì)象增加功能,這些功能可以再動(dòng)態(tài)地撤銷(xiāo)。
● 需要為一批的兄弟類(lèi)進(jìn)行改裝或加裝功能,當(dāng)然是首選裝飾模式。
12.策略模式(Strategy Pattern)
定義:Define a family of algorithms,encapsulate each one,and make them interchangeable.(定義一組算法,將每個(gè)算法都封裝起來(lái),并且使它們之間可以互換。)
● Context封裝角色
它也叫做上下文角色,起承上啟下封裝作用,屏蔽高層模塊對(duì)策略、算法的直接訪問(wèn),封裝可能存在的變化。
● Strategy抽象策略角色
策略、算法家族的抽象,通常為接口,定義每個(gè)策略或算法必須具有的方法和屬性。各位看官可能要問(wèn)了,類(lèi)圖中的AlgorithmInterface是什么意思,嘿嘿,algorithm是“運(yùn)算法則”的意思,結(jié)合起來(lái)意思就明白了吧。
● ConcreteStrategy具體策略角色(多個(gè))
實(shí)現(xiàn)抽象策略中的操作,該類(lèi)含有具體的算法。
使用場(chǎng)景:
● 多個(gè)類(lèi)只有在算法或行為上稍有不同的場(chǎng)景。
● 算法需要自由切換的場(chǎng)景。
● 需要屏蔽算法規(guī)則的場(chǎng)景。
注意事項(xiàng):具體策略數(shù)量超過(guò)4個(gè),則需要考慮使用混合模式
策略模式擴(kuò)展:策略枚舉
public enum Calculator {
//加法運(yùn)算
ADD(“+”){
public int exec(int a,int b){
return a+b;
}
},
//減法運(yùn)算
SUB(“-“){
public int exec(int a,int b){
return a - b;
}
};
String value = “”;
//定義成員值類(lèi)型
private Calculator(String _value){
this.value = _value;
}
//獲得枚舉成員的值
public String getValue(){
return this.value;
}
//聲明一個(gè)抽象函數(shù)
public abstract int exec(int a,int b);
}
定義:
● 它是一個(gè)枚舉。
● 它是一個(gè)濃縮了的策略模式的枚舉。
注意:
受枚舉類(lèi)型的限制,每個(gè)枚舉項(xiàng)都是public、final、static的,擴(kuò)展性受到了一定的約束,因此在系統(tǒng)開(kāi)發(fā)中,策略枚舉一般擔(dān)當(dāng)不經(jīng)常發(fā)生變化的角色。
致命缺陷:
所有的策略都需要暴露出去,由客戶(hù)端決定使用哪一個(gè)策略。
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.(將一個(gè)類(lèi)的接口變換成客戶(hù)端所期待的另一種接口,從而使原本因接口不匹配而無(wú)法在一起工作的兩個(gè)類(lèi)能夠在一起工作。)
類(lèi)適配器:
● Target目標(biāo)角色
該角色定義把其他類(lèi)轉(zhuǎn)換為何種接口,也就是我們的期望接口,例子中的IUserInfo接口就是目標(biāo)角色。
● Adaptee源角色
你想把誰(shuí)轉(zhuǎn)換成目標(biāo)角色,這個(gè)“誰(shuí)”就是源角色,它是已經(jīng)存在的、運(yùn)行良好的類(lèi)或?qū)ο?#xff0c;經(jīng)過(guò)適配器角色的包裝,它會(huì)成為一個(gè)嶄新、靚麗的角色。
● Adapter適配器角色
適配器模式的核心角色,其他兩個(gè)角色都是已經(jīng)存在的角色,而適配器角色是需要新建立的,它的職責(zé)非常簡(jiǎn)單:把源角色轉(zhuǎn)換為目標(biāo)角色,怎么轉(zhuǎn)換?通過(guò)繼承或是類(lèi)關(guān)聯(lián)的方式。
使用場(chǎng)景:
你有動(dòng)機(jī)修改一個(gè)已經(jīng)投產(chǎn)中的接口時(shí),適配器模式可能是最適合你的模式。比如系統(tǒng)擴(kuò)展了,需要使用一個(gè)已有或新建立的類(lèi),但這個(gè)類(lèi)又不符合系統(tǒng)的接口,怎么辦?使用適配器模式,這也是我們例子中提到的。
注意事項(xiàng):
詳細(xì)設(shè)計(jì)階段不要考慮使用適配器模式,使用主要場(chǎng)景為擴(kuò)展應(yīng)用中。
對(duì)象適配器:
對(duì)象適配器和類(lèi)適配器的區(qū)別:
類(lèi)適配器是類(lèi)間繼承,對(duì)象適配器是對(duì)象的合成關(guān)系,也可以說(shuō)是類(lèi)的關(guān)聯(lián)關(guān)系,這是兩者的根本區(qū)別。(實(shí)際項(xiàng)目中對(duì)象適配器使用到的場(chǎng)景相對(duì)比較多)。
14.迭代器模式(Iterator Pattern)
定義:Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.(它提供一種方法訪問(wèn)一個(gè)容器對(duì)象中各個(gè)元素,而又不需暴露該對(duì)象的內(nèi)部細(xì)節(jié)。)
● Iterator抽象迭代器
抽象迭代器負(fù)責(zé)定義訪問(wèn)和遍歷元素的接口,而且基本上是有固定的3個(gè)方法:first()獲得第一個(gè)元素,next()訪問(wèn)下一個(gè)元素,isDone()是否已經(jīng)訪問(wèn)到底部(Java叫做hasNext()方法)。
● ConcreteIterator具體迭代器
具體迭代器角色要實(shí)現(xiàn)迭代器接口,完成容器元素的遍歷。
● Aggregate抽象容器
容器角色負(fù)責(zé)提供創(chuàng)建具體迭代器角色的接口,必然提供一個(gè)類(lèi)似createIterator()這樣的方法,在Java中一般是iterator()方法。
● Concrete Aggregate具體容器
具體容器實(shí)現(xiàn)容器接口定義的方法,創(chuàng)建出容納迭代器的對(duì)象。
ps:迭代器模式已經(jīng)被淘汰,java中已經(jīng)把迭代器運(yùn)用到各個(gè)聚集類(lèi)(collection)中了,使用java自帶的迭代器就已經(jīng)滿(mǎn)足我們的需求了。
15.組合模式((Composite Pattern))
定義:Compose objects into tree structures to represent part-whole hierarchies.Composite lets clients treat individual objects and compositions of objects uniformly.(將對(duì)象組合成樹(shù)形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),使得用戶(hù)對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。)
● Component抽象構(gòu)件角色
定義參加組合對(duì)象的共有方法和屬性,可以定義一些默認(rèn)的行為或?qū)傩?#xff0c;比如我們例子中的getInfo就封裝到了抽象類(lèi)中。
● Leaf葉子構(gòu)件
葉子對(duì)象,其下再也沒(méi)有其他的分支,也就是遍歷的最小單位。
● Composite樹(shù)枝構(gòu)件
樹(shù)枝對(duì)象,它的作用是組合樹(shù)枝節(jié)點(diǎn)和葉子節(jié)點(diǎn)形成一個(gè)樹(shù)形結(jié)構(gòu)。
樹(shù)枝構(gòu)件的通用代碼:
public class Composite extends Component {
//構(gòu)件容器
private ArrayList componentArrayList = new ArrayList();
//增加一個(gè)葉子構(gòu)件或樹(shù)枝構(gòu)件
public void add(Component component){
this.componentArrayList.add(component);
}
//刪除一個(gè)葉子構(gòu)件或樹(shù)枝構(gòu)件
public void remove(Component component){
this.componentArrayList.remove(component);
}
//獲得分支下的所有葉子構(gòu)件和樹(shù)枝構(gòu)件
public ArrayList getChildren(){
return this.componentArrayList;
}
}
使用場(chǎng)景:
● 維護(hù)和展示部分-整體關(guān)系的場(chǎng)景,如樹(shù)形菜單、文件和文件夾管理。
● 從一個(gè)整體中能夠獨(dú)立出部分模塊或功能的場(chǎng)景。
注意:
只要是樹(shù)形結(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.(定義對(duì)象間一種一對(duì)多的依賴(lài)關(guān)系,使得每當(dāng)一個(gè)對(duì)象改變狀態(tài),則所有依賴(lài)于它的對(duì)象都會(huì)得到通知并被自動(dòng)更新。)
● Subject被觀察者
定義被觀察者必須實(shí)現(xiàn)的職責(zé),它必須能夠動(dòng)態(tài)地增加、取消觀察者。它一般是抽象類(lèi)或者是實(shí)現(xiàn)類(lèi),僅僅完成作為被觀察者必須實(shí)現(xiàn)的職責(zé):管理觀察者并通知觀察者。
● Observer觀察者
觀察者接收到消息后,即進(jìn)行update(更新方法)操作,對(duì)接收到的信息進(jìn)行處理。
● ConcreteSubject具體的被觀察者
定義被觀察者自己的業(yè)務(wù)邏輯,同時(shí)定義對(duì)哪些事件進(jìn)行通知。
● ConcreteObserver具體的觀察者
每個(gè)觀察在接收到消息后的處理反應(yīng)是不同,各個(gè)觀察者有自己的處理邏輯。
被觀察者通用代碼:
public abstract class Subject {
//定義一個(gè)觀察者數(shù)組
private Vector obsVector = new Vector();
//增加一個(gè)觀察者
public void addObserver(Observer o){
this.obsVector.add(o);
}
//刪除一個(gè)觀察者
public void delObserver(Observer o){
this.obsVector.remove(o);
}
//通知所有觀察者
public void notifyObservers(){
for(Observer o:this.obsVector){
o.update();
}
}
}
使用場(chǎng)景:
● 關(guān)聯(lián)行為場(chǎng)景。需要注意的是,關(guān)聯(lián)行為是可拆分的,而不是“組合”關(guān)系。
● 事件多級(jí)觸發(fā)場(chǎng)景。
● 跨系統(tǒng)的消息交換場(chǎng)景,如消息隊(duì)列的處理機(jī)制。
注意:
● 廣播鏈的問(wèn)題
在一個(gè)觀察者模式中最多出現(xiàn)一個(gè)對(duì)象既是觀察者也是被觀察者,也就是說(shuō)消息最多轉(zhuǎn)發(fā)一次(傳遞兩次)。
● 異步處理問(wèn)題
觀察者比較多,而且處理時(shí)間比較長(zhǎng),采用異步處理來(lái)考慮線(xiàn)程安全和隊(duì)列的問(wèn)題。
17.門(mén)面模式(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.(要求一個(gè)子系統(tǒng)的外部與其內(nèi)部的通信必須通過(guò)一個(gè)統(tǒng)一的對(duì)象進(jìn)行。門(mén)面模式提供一個(gè)高層次的接口,使得子系統(tǒng)更易于使用。)
● Facade門(mén)面角色
客戶(hù)端可以調(diào)用這個(gè)角色的方法。此角色知曉子系統(tǒng)的所有功能和責(zé)任。一般情況下,本角色會(huì)將所有從客戶(hù)端發(fā)來(lái)的請(qǐng)求委派到相應(yīng)的子系統(tǒng)去,也就說(shuō)該角色沒(méi)有實(shí)際的業(yè)務(wù)邏輯,只是一個(gè)委托類(lèi)。
● subsystem子系統(tǒng)角色
可以同時(shí)有一個(gè)或者多個(gè)子系統(tǒng)。每一個(gè)子系統(tǒng)都不是一個(gè)單獨(dú)的類(lèi),而是一個(gè)類(lèi)的集合。子系統(tǒng)并不知道門(mén)面的存在。對(duì)于子系統(tǒng)而言,門(mén)面僅僅是另外一個(gè)客戶(hù)端而已。
使用場(chǎng)景:
● 為一個(gè)復(fù)雜的模塊或子系統(tǒng)提供一個(gè)供外界訪問(wèn)的接口
● 子系統(tǒng)相對(duì)獨(dú)立——外界對(duì)子系統(tǒng)的訪問(wèn)只要黑箱操作即可
● 預(yù)防低水平人員帶來(lái)的風(fēng)險(xiǎn)擴(kuò)散
注意:
●一個(gè)子系統(tǒng)可以有多個(gè)門(mén)面
●門(mén)面不參與子系統(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.(在不破壞封裝性的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。這樣以后就可將該對(duì)象恢復(fù)到原先保存的狀態(tài)。)
● Originator發(fā)起人角色
記錄當(dāng)前時(shí)刻的內(nèi)部狀態(tài),負(fù)責(zé)定義哪些屬于備份范圍的狀態(tài),負(fù)責(zé)創(chuàng)建和恢復(fù)備忘錄數(shù)據(jù)。
● Memento備忘錄角色(簡(jiǎn)單的javabean)
負(fù)責(zé)存儲(chǔ)Originator發(fā)起人對(duì)象的內(nèi)部狀態(tài),在需要的時(shí)候提供發(fā)起人需要的內(nèi)部狀態(tài)。
● Caretaker備忘錄管理員角色(簡(jiǎn)單的javabean)
對(duì)備忘錄進(jìn)行管理、保存和提供備忘錄。
使用場(chǎng)景:
● 需要保存和恢復(fù)數(shù)據(jù)的相關(guān)狀態(tài)場(chǎng)景。
● 提供一個(gè)可回滾(rollback)的操作。
● 需要監(jiān)控的副本場(chǎng)景中。
● 數(shù)據(jù)庫(kù)連接的事務(wù)管理就是用的備忘錄模式。
注意:
●備忘錄的生命期
●備忘錄的性能
不要在頻繁建立備份的場(chǎng)景中使用備忘錄模式(比如一個(gè)for循環(huán)中)。
clone方式備忘錄:
● 發(fā)起人角色融合了發(fā)起人角色和備忘錄角色,具有雙重功效
多狀態(tài)的備忘錄模式
● 增加了一個(gè)BeanUtils類(lèi),其中backupProp是把發(fā)起人的所有屬性值轉(zhuǎn)換到HashMap中,方便備忘錄角色存儲(chǔ)。restoreProp方法則是把HashMap中的值返回到發(fā)起人角色中。
BeanUtil工具類(lèi)代碼:
public class BeanUtils {
//把bean的所有屬性及數(shù)值放入到Hashmap中
public static HashMap
19.訪問(wèn)者模式(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——抽象訪問(wèn)者
抽象類(lèi)或者接口,聲明訪問(wèn)者可以訪問(wèn)哪些元素,具體到程序中就是visit方法的參數(shù)定義哪些對(duì)象是可以被訪問(wèn)的。
● ConcreteVisitor——具體訪問(wèn)者
它影響訪問(wèn)者訪問(wèn)到一個(gè)類(lèi)后該怎么干,要做什么事情。
● Element——抽象元素
接口或者抽象類(lèi),聲明接受哪一類(lèi)訪問(wèn)者訪問(wèn),程序上是通過(guò)accept方法中的參數(shù)來(lái)定義的。
● ConcreteElement——具體元素
實(shí)現(xiàn)accept方法,通常是visitor.visit(this),基本上都形成了一種模式了。
● ObjectStruture——結(jié)構(gòu)對(duì)象
元素產(chǎn)生者,一般容納在多個(gè)不同類(lèi)、不同接口的容器,如List、Set、Map等,在項(xiàng)目中,一般很少抽象出這個(gè)角色。
使用場(chǎng)景:
● 一個(gè)對(duì)象結(jié)構(gòu)包含很多類(lèi)對(duì)象,它們有不同的接口,而你想對(duì)這些對(duì)象實(shí)施一些依賴(lài)于其具體類(lèi)的操作,也就說(shuō)是用迭代器模式已經(jīng)不能勝任的情景。
● 需要對(duì)一個(gè)對(duì)象結(jié)構(gòu)中的對(duì)象進(jìn)行很多不同并且不相關(guān)的操作,而你想避免讓這些操作“污染”這些對(duì)象的類(lèi)。
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)一個(gè)對(duì)象內(nèi)在狀態(tài)改變時(shí)允許其改變行為,這個(gè)對(duì)象看起來(lái)像改變了其類(lèi)。)
● State——抽象狀態(tài)角色
接口或抽象類(lèi),負(fù)責(zé)對(duì)象狀態(tài)定義,并且封裝環(huán)境角色以實(shí)現(xiàn)狀態(tài)切換。
● ConcreteState——具體狀態(tài)角色
每一個(gè)具體狀態(tài)必須完成兩個(gè)職責(zé):本狀態(tài)的行為管理以及趨向狀態(tài)處理,通俗地說(shuō),就是本狀態(tài)下要做的事情,以及本狀態(tài)如何過(guò)渡到其他狀態(tài)。
● Context——環(huán)境角色
定義客戶(hù)端需要的接口,并且負(fù)責(zé)具體狀態(tài)的切換。
使用場(chǎng)景:
● 行為隨狀態(tài)改變而改變的場(chǎng)景
這也是狀態(tài)模式的根本出發(fā)點(diǎn),例如權(quán)限設(shè)計(jì),人員的狀態(tài)不同即使執(zhí)行相同的行為結(jié)果也會(huì)不同,在這種情況下需要考慮使用狀態(tài)模式。
● 條件、分支判斷語(yǔ)句的替代者
注意:
狀態(tài)模式適用于當(dāng)某個(gè)對(duì)象在它的狀態(tài)發(fā)生改變時(shí),它的行為也隨著發(fā)生比較大的變化,也就是說(shuō)在行為受狀態(tài)約束的情況下可以使用狀態(tài)模式,而且使用時(shí)對(duì)象的狀態(tài)最好不要超過(guò)5個(gè)。
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.(給定一門(mén)語(yǔ)言,定義它的文法的一種表示,并定義一個(gè)解釋器,該解釋器使用該表示來(lái)解釋語(yǔ)言中的句子。)
● AbstractExpression——抽象解釋器
具體的解釋任務(wù)由各個(gè)實(shí)現(xiàn)類(lèi)完成,具體的解釋器分別由TerminalExpression和Non-terminalExpression完成。
● TerminalExpression——終結(jié)符表達(dá)式
實(shí)現(xiàn)與文法中的元素相關(guān)聯(lián)的解釋操作,通常一個(gè)解釋器模式中只有一個(gè)終結(jié)符表達(dá)式,但有多個(gè)實(shí)例,對(duì)應(yīng)不同的終結(jié)符。具體到我們例子就是VarExpression類(lèi),表達(dá)式中的每個(gè)終結(jié)符都在棧中產(chǎn)生了一個(gè)VarExpression對(duì)象。
● NonterminalExpression——非終結(jié)符表達(dá)式
文法中的每條規(guī)則對(duì)應(yīng)于一個(gè)非終結(jié)表達(dá)式,具體到我們的例子就是加減法規(guī)則分別對(duì)應(yīng)到AddExpression和SubExpression兩個(gè)類(lèi)。非終結(jié)符表達(dá)式根據(jù)邏輯的復(fù)雜程度而增加,原則上每個(gè)文法規(guī)則都對(duì)應(yīng)一個(gè)非終結(jié)符表達(dá)式。
● Context——環(huán)境角色
具體到我們的例子中是采用HashMap代替。
使用場(chǎng)景:
● 重復(fù)發(fā)生的問(wèn)題可以使用解釋器模式
● 一個(gè)簡(jiǎn)單語(yǔ)法需要解釋的場(chǎng)景
注意:
盡量不要在重要的模塊中使用解釋器模式,否則維護(hù)會(huì)是一個(gè)很大的問(wèn)題。在項(xiàng)目中可以使用shell、JRuby、Groovy等腳本語(yǔ)言來(lái)代替解釋器模式,彌補(bǔ)Java編譯型語(yǔ)言的不足。
22.享元模式(Flyweight Pattern)
定義:Use sharing to support large numbers of fine-grained objects efficiently.(使用共享對(duì)象可有效地支持大量的細(xì)粒度的對(duì)象。)
對(duì)象的信息分為兩個(gè)部分:內(nèi)部狀態(tài)(intrinsic)與外部狀態(tài)(extrinsic)。
● 內(nèi)部狀態(tài)
內(nèi)部狀態(tài)是對(duì)象可共享出來(lái)的信息,存儲(chǔ)在享元對(duì)象內(nèi)部并且不會(huì)隨環(huán)境改變而改變。
● 外部狀態(tài)
外部狀態(tài)是對(duì)象得以依賴(lài)的一個(gè)標(biāo)記,是隨環(huán)境改變而改變的、不可以共享的狀態(tài)。
● Flyweight——抽象享元角色
它簡(jiǎn)單地說(shuō)就是一個(gè)產(chǎn)品的抽象類(lèi),同時(shí)定義出對(duì)象的外部狀態(tài)和內(nèi)部狀態(tài)的接口或?qū)崿F(xiàn)。
● ConcreteFlyweight——具體享元角色
具體的一個(gè)產(chǎn)品類(lèi),實(shí)現(xiàn)抽象角色定義的業(yè)務(wù)。該角色中需要注意的是內(nèi)部狀態(tài)處理應(yīng)該與環(huán)境無(wú)關(guān),不應(yīng)該出現(xiàn)一個(gè)操作改變了內(nèi)部狀態(tài),同時(shí)修改了外部狀態(tài),這是絕對(duì)不允許的。
● unsharedConcreteFlyweight——不可共享的享元角色
不存在外部狀態(tài)或者安全要求(如線(xiàn)程安全)不能夠使用共享技術(shù)的對(duì)象,該對(duì)象一般不會(huì)出現(xiàn)在享元工廠中。
● FlyweightFactory——享元工廠
職責(zé)非常簡(jiǎn)單,就是構(gòu)造一個(gè)池容器,同時(shí)提供從池中獲得對(duì)象的方法。
享元工廠的代碼:
public class FlyweightFactory {
//定義一個(gè)池容器
private static HashMap
23.橋梁模式(Bridge Pattern)
定義:Decouple an abstraction from its implementation so that the two can vary independently.(將抽象和實(shí)現(xiàn)解耦,使得兩者可以獨(dú)立地變化。)
● Abstraction——抽象化角色
它的主要職責(zé)是定義出該角色的行為,同時(shí)保存一個(gè)對(duì)實(shí)現(xiàn)化角色的引用,該角色一般是抽象類(lèi)。
● Implementor——實(shí)現(xiàn)化角色
它是接口或者抽象類(lèi),定義角色必需的行為和屬性。
● RefinedAbstraction——修正抽象化角色
它引用實(shí)現(xiàn)化角色對(duì)抽象化角色進(jìn)行修正。
● ConcreteImplementor——具體實(shí)現(xiàn)化角色
它實(shí)現(xiàn)接口或抽象類(lèi)定義的方法和屬性。
使用場(chǎng)景:
● 不希望或不適用使用繼承的場(chǎng)景
● 接口或抽象類(lèi)不穩(wěn)定的場(chǎng)景
● 重用性要求較高的場(chǎng)景
注意:
發(fā)現(xiàn)類(lèi)的繼承有N層時(shí),可以考慮使用橋梁模式。橋梁模式主要考慮如何拆分抽象和實(shí)現(xiàn)。
設(shè)計(jì)原則:
●Single Responsibility Principle:單一職責(zé)原則
單一職責(zé)原則有什么好處:
● 類(lèi)的復(fù)雜性降低,實(shí)現(xiàn)什么職責(zé)都有清晰明確的定義;
● 可讀性提高,復(fù)雜性降低,那當(dāng)然可讀性提高了;
● 可維護(hù)性提高,可讀性提高,那當(dāng)然更容易維護(hù)了;
●變更引起的風(fēng)險(xiǎn)降低,變更是必不可少的,如果接口的單一職責(zé)做得好,一個(gè)接口修改只對(duì)相應(yīng)的實(shí)現(xiàn)類(lèi)有影響,對(duì)其他的接口無(wú)影響,這對(duì)系統(tǒng)的擴(kuò)展性、維護(hù)性都有非常大的幫助。
ps:接口一定要做到單一職責(zé),類(lèi)的設(shè)計(jì)盡量做到只有一個(gè)原因引起變化。
單一職責(zé)原則提出了一個(gè)編寫(xiě)程序的標(biāo)準(zhǔn),用“職責(zé)”或“變化原因”來(lái)衡量接口或類(lèi)設(shè)計(jì)得是否優(yōu)良,但是“職責(zé)”和“變化原因”都是不可度量的,因項(xiàng)目而異,因環(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.
(所有引用基類(lèi)的地方必須能透明地使用其子類(lèi)的對(duì)象。)
通俗點(diǎn)講,只要父類(lèi)能出現(xiàn)的地方子類(lèi)就可以出現(xiàn),而且替換為子類(lèi)也不會(huì)產(chǎn)生任何錯(cuò)誤或異常,使用者可能根本就不需要知道是父類(lèi)還是子類(lèi)。但是,反過(guò)來(lái)就不行了,有子類(lèi)出現(xiàn)的地方,父類(lèi)未必就能適應(yīng)。
定義中包含的四層含義:
1.子類(lèi)必須完全實(shí)現(xiàn)父類(lèi)的方法
2.子類(lèi)可以有自己的個(gè)性
3.覆蓋或?qū)崿F(xiàn)父類(lèi)的方法時(shí)輸入?yún)?shù)可以被放大
如果父類(lèi)的輸入?yún)?shù)類(lèi)型大于子類(lèi)的輸入?yún)?shù)類(lèi)型,會(huì)出現(xiàn)父類(lèi)存在的地方,子類(lèi)未必會(huì)存在,因?yàn)橐坏┌炎宇?lèi)作為參數(shù)傳入,調(diào)用者很可能進(jìn)入子類(lèi)的方法范疇。
父類(lèi)的一個(gè)方法的返回值是一個(gè)類(lèi)型T,子類(lèi)的相同方法(重載或覆寫(xiě))的返回值為S,那么里氏替換原則就要求S必須小于等于T,也就是說(shuō),要么S和T是同一個(gè)類(lèi)型,要么S是T的子類(lèi)。
● Interface Segregation Principle:接口隔離原則
接口分為兩種:
實(shí)例接口(Object Interface):Java中的類(lèi)也是一種接口
類(lèi)接口(Class Interface): Java中經(jīng)常使用Interface關(guān)鍵字定義的接口
隔離:建立單一接口,不要建立臃腫龐大的接口;即接口要盡量細(xì)化,同時(shí)接口中的方法要盡量少。
接口隔離原則與單一職責(zé)原則的不同:接口隔離原則與單一職責(zé)的審視角度是不相同的,單一職責(zé)要求的是類(lèi)和接口職責(zé)單一,注重的是職責(zé),這是業(yè)務(wù)邏輯上的劃分,而接口隔離原則要求接口的方法盡量少。
● Dependence Inversion Principle:依賴(lài)倒置原則
原始定義:
①高層模塊不應(yīng)該依賴(lài)低層模塊,兩者都應(yīng)該依賴(lài)其抽象;
②抽象不應(yīng)該依賴(lài)細(xì)節(jié)(實(shí)現(xiàn)類(lèi));
③細(xì)節(jié)應(yīng)該依賴(lài)抽象。
依賴(lài)倒置原則在java語(yǔ)言中的體現(xiàn):
①模塊間的依賴(lài)通過(guò)抽象發(fā)生,實(shí)現(xiàn)類(lèi)之間不發(fā)生直接的依賴(lài)關(guān)系,其依賴(lài)關(guān)系是通過(guò)接口或抽象類(lèi)產(chǎn)生的;
②接口或抽象類(lèi)不依賴(lài)于實(shí)現(xiàn)類(lèi);
③實(shí)現(xiàn)類(lèi)依賴(lài)接口或抽象類(lèi)。
依賴(lài)的三種寫(xiě)法:
①構(gòu)造函數(shù)傳遞依賴(lài)對(duì)象(構(gòu)造函數(shù)注入)
②Setter方法傳遞依賴(lài)對(duì)象(setter依賴(lài)注入)
③接口聲明依賴(lài)對(duì)象(接口注入)
使用原則:
依賴(lài)倒置原則的本質(zhì)就是通過(guò)抽象(接口或抽象類(lèi))使各個(gè)類(lèi)或模塊的實(shí)現(xiàn)彼此獨(dú)立,不互相影響,實(shí)現(xiàn)模塊間的松耦合,我們?cè)趺丛陧?xiàng)目中使用這個(gè)規(guī)則呢?只要遵循以下的幾個(gè)規(guī)則就可以:
①每個(gè)類(lèi)盡量都有接口或抽象類(lèi),或者抽象類(lèi)和接口兩者都具備
②變量的表面類(lèi)型盡量是接口或者是抽象類(lèi)
③任何類(lèi)都不應(yīng)該從具體類(lèi)派生(只要不超過(guò)兩層的繼承是可以忍受的)
④盡量不要復(fù)寫(xiě)基類(lèi)的方法
⑤結(jié)合里氏替換原則使用
●Open Closed Principle:開(kāi)閉原則
定義:軟件實(shí)體應(yīng)該對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。
其含義是說(shuō)一個(gè)軟件實(shí)體應(yīng)該通過(guò)擴(kuò)展來(lái)實(shí)現(xiàn)變化,而不是通過(guò)修改已有的代碼來(lái)實(shí)現(xiàn)變化。
軟件實(shí)體:項(xiàng)目或軟件產(chǎn)品中按照一定的邏輯規(guī)則劃分的模塊、抽象和類(lèi)、方法。
變化的三種類(lèi)型:
①邏輯變化
只變化一個(gè)邏輯,而不涉及其他模塊,比如原有的一個(gè)算法是a*b+c,現(xiàn)在需要修改為a*b*c,可以通過(guò)修改原有類(lèi)中的方法的方式來(lái)完成,前提條件是所有依賴(lài)或關(guān)聯(lián)類(lèi)都按照相同的邏輯處理。
②子模塊變化
一個(gè)模塊變化,會(huì)對(duì)其他的模塊產(chǎn)生影響,特別是一個(gè)低層次的模塊變化必然引起高層模塊的變化,因此在通過(guò)擴(kuò)展完成變化時(shí),高層次的模塊修改是必然的。
③可見(jiàn)視圖變化
可見(jiàn)視圖是提供給客戶(hù)使用的界面,如JSP程序、Swing界面等,該部分的變化一般會(huì)引起連鎖反應(yīng)(特別是在國(guó)內(nèi)做項(xiàng)目,做歐美的外包項(xiàng)目一般不會(huì)影響太大)??梢酝ㄟ^(guò)擴(kuò)展來(lái)完成變化,這要看我們?cè)械脑O(shè)計(jì)是否靈活
總結(jié)
以上是生活随笔為你收集整理的读书笔记 23种设计模式总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python列表_Python列表抽象
- 下一篇: 流畅的python第一章_《流畅的Pyt