gof分類:
創(chuàng)建型模式旁钧,共五種:工廠方法模式吸重、抽象工廠模式、單例模式歪今、建造者模式嚎幸、原型模式。
結(jié)構(gòu)型模式寄猩,共七種:適配器模式嫉晶、裝飾器模式、代理模式、外觀模式替废、橋接模式箍铭、組合模式、享元模式椎镣。
行為型模式坡疼,共十一種:策略模式、模板方法模式衣陶、觀察者模式柄瑰、迭代子模式、責(zé)任鏈模式剪况、命令模式教沾、備忘錄模式、狀態(tài)模式译断、訪問者模式授翻、中介者模式、解釋器模式孙咪。
這里只總結(jié)幾種比較重要的:
———————————————————————————————————————
一堪唐、創(chuàng)建型:
1.簡單工廠模式
簡單工廠模式通常就是這樣,一個工廠類 XxxFactory翎蹈,里面有一個靜態(tài)方法淮菠,根據(jù)我們不同的參數(shù),使用swtich +case 返回不同的派生自同一個父類(同一職責(zé))(或?qū)崿F(xiàn)同一接口)的實(shí)例對象荤堪。
把或者各個類型的都統(tǒng)一放到./工廠產(chǎn)品/目錄下,工廠傳入要匹配的類型, 以匹配類型為文件名合陵。需要實(shí)例化的時候就require該文件,這樣也保證了各個開發(fā)人員的代碼不沖突澄阳。后期也易擴(kuò)展拥知,新增一種類型的用戶,只需新增一個類型的文件即可符合開閉原則碎赢。
2.工廠模式(需要使用兩個或兩個以上的工廠時)
3.抽象工廠模式(通過抽象產(chǎn)品來抽象了工廠)
涉及定義某個產(chǎn)品的一系列附件的集合時, 不再定義組件工廠,直接定義產(chǎn)品工廠,由產(chǎn)品工廠來定義所需組件
4.單例模式
1低剔、單例類只能有一個實(shí)例。
2肮塞、單例類必須自己創(chuàng)建自己的唯一實(shí)例襟齿。
3、單例類必須給所有其他對象提供這一實(shí)例峦嗤。
懶漢式單例(在第一次調(diào)用的時候?qū)嵗约?:
public class Singleton {
//不再提供給其他的地方實(shí)例化
private Singleton() {}
private static Singleton single=null;
//靜態(tài)工廠方法,Singleton的唯一實(shí)例只能通過getInstance()方法訪問蕊唐。為空的時候才生產(chǎn)
//如果把實(shí)例寫在成員變量里則法不能把其他不需要實(shí)例的常用方法放入這里,會導(dǎo)致在不需要時創(chuàng)建實(shí)例。
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
懶漢式單例的實(shí)現(xiàn)沒有考慮線程安全問題烁设,它是線程不安全的,并發(fā)環(huán)境下很可能出現(xiàn)多個Singleton實(shí)例,要實(shí)現(xiàn)線程安全装黑,有以下三種方式(只記錄兩種):
1副瀑、在getInstance方法上加同步synchronized
2、靜態(tài)內(nèi)部類(既實(shí)現(xiàn)了線程安全恋谭,又避免了同步帶來的性能影響)
Java機(jī)制規(guī)定糠睡,內(nèi)部類只有在調(diào)用內(nèi)部類方法第一次調(diào)用的時候才會被加載(實(shí)現(xiàn)了延遲加載效果),而且其加載過程是線程安全的(實(shí)現(xiàn)線程安全)疚颊。內(nèi)部類加載的時候?qū)嵗淮蝘nstance狈孔。
另外,外部類加載的時候,內(nèi)部類不會被加載材义,靜態(tài)內(nèi)部類只是調(diào)用的時候用了外部類的名字而已均抽。
public class Singleton {
private static class LazyHolder { //靜態(tài)類懶漢式視為延遲加載的餓漢式
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
餓漢式單例(餓漢式單例類.在類初始化時,已經(jīng)自行實(shí)例化,天生是線程安全的):
public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
//靜態(tài)工廠方法
public static Singleton1 getInstance() {
return single;
}
}
5.建造者模式 參考
是將一個復(fù)雜的對象的構(gòu)建與它的表示分離其掂,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示油挥。
(例如造汽車與買汽車)
一般包括以下幾個角色:
- builder(抽象建造者):給出一個抽象結(jié)論,以規(guī)范產(chǎn)品對象的各個組成成分的建造款熬。這個接口規(guī)定要實(shí)現(xiàn)復(fù)雜對象的那些部分的創(chuàng)建深寥,并不涉及具體的對象部件的創(chuàng)建。
- ConcreteBuilder(具體建造者):實(shí)現(xiàn)Builder接口贤牛,針對不同的商業(yè)邏輯惋鹅,具體化復(fù)雜對象的各部分的創(chuàng)建。在構(gòu)造過程完成后殉簸,提供產(chǎn)品的實(shí)例负饲。
- Director(指導(dǎo)者):調(diào)用具體建造者來創(chuàng)建復(fù)雜對象的各個部分,在指導(dǎo)者中不涉及具體產(chǎn)品的信息喂链,只負(fù)責(zé)保證對象各部分完整創(chuàng)建或按某種順序創(chuàng)建返十。
- Product(產(chǎn)品類):要創(chuàng)建的復(fù)雜對象。
適用場景
需要生產(chǎn)的產(chǎn)品對象有復(fù)雜的內(nèi)部結(jié)構(gòu)椭微。
需要生產(chǎn)的產(chǎn)品對象的屬性相互依賴洞坑,建造者模式可以強(qiáng)迫生成順序。
在對象創(chuàng)建過程中會使用到系統(tǒng)中的一些其它對象蝇率,這些對象在產(chǎn)品對象的創(chuàng)建過程中不易得到迟杂。
———————————————————————————————————————
二、結(jié)構(gòu)型
1.適配器模式
適配器就是一種適配中間件本慕,它存在于不匹配的二者之間排拷,用于連接二者,將不匹配變得匹配锅尘,簡單點(diǎn)理解就是平常所見的轉(zhuǎn)接頭监氢,轉(zhuǎn)換器之類的存在布蔗。
適配器模式有兩種:類適配器、對象適配器浪腐、接口適配器
前二者在實(shí)現(xiàn)上有些許區(qū)別纵揍,作用一樣,第三個接口適配器差別較大议街。
類適配器模式:
當(dāng)我們要訪問的接口A中沒有我們想要的方法 泽谨,卻在另一個接口B中發(fā)現(xiàn)了合適的方法,我們又不能改變訪問接口A特漩,在這種情況下吧雹,我們可以定義一個適配器p來進(jìn)行中轉(zhuǎn),這個適配器p要實(shí)現(xiàn)我們訪問的接口A涂身,這樣我們就能繼續(xù)訪問當(dāng)前接口A中的方法(雖然它目前不是我們的菜)雄卷,然后再繼承接口B的實(shí)現(xiàn)類BB,這樣就完成了一個簡單的類適配器访得。
1 public class Adapter extends Usber implements Ps2 {
2 //在實(shí)現(xiàn)自己接口A的同時繼承要額外訪問的接口B的實(shí)現(xiàn);類Usber
3 @Override
4 public void isPs2() {
5 isUsb();
6 }
7
8 }
對象適配器模式 :
我們可以定義一個適配器p來進(jìn)行中轉(zhuǎn)龙亲,這個適配器p要實(shí)現(xiàn)我們訪問的接口A,這樣我們就能繼續(xù)訪問當(dāng)前接口A中的方法(雖然它目前不是我們的菜)悍抑,然后在適配器P中定義私有變量C(對象)(B接口指向變量名)鳄炉,再定義一個帶參數(shù)的構(gòu)造器用來為對象C賦值,再在A接口的方法實(shí)現(xiàn)中使用對象C調(diào)用其來源于B接口的方法搜骡。
1 public class Adapter implements Ps2 {
2 //
3 private Usb usb;
4 public Adapter(Usb usb){
5 this.usb = usb;
6 }
7 @Override
8 public void isPs2() {
9 usb.isUsb();
10 }
11
12 }
接口適配器模式 :
當(dāng)存在這樣一個接口拂盯,其中定義了N多的方法,而我們現(xiàn)在卻只想使用其中的一個到幾個方法记靡,如果我們直接實(shí)現(xiàn)接口谈竿,那么我們要對所有的方法進(jìn)行實(shí)現(xiàn),哪怕我們僅僅是對不需要的方法進(jìn)行置空(只寫一對大括號摸吠,不做具體方法實(shí)現(xiàn))也會導(dǎo)致這個類變得臃腫空凸,調(diào)用也不方便,這時我們可以使用一個抽象類作為中間件寸痢,即適配器呀洲,用這個抽象類實(shí)現(xiàn)接口,而在抽象類中所有的方法都進(jìn)行置空啼止,那么我們在創(chuàng)建抽象類的繼承類道逗,而且重寫我們需要使用的那幾個方法即可。
使用場景:
(1)類:想要使用一個已經(jīng)存在的類献烦,但是它卻不符合現(xiàn)有的接口規(guī)范滓窍,導(dǎo)致無法直接去訪問,這時創(chuàng)建一個適配器就能間接去訪問這個類中的方法巩那。
(2)對象:我們有一個類吏夯,想將其設(shè)計為可重用的類(可被多處訪問)此蜈,我們可以創(chuàng)建適配器來將這個類來適配其他沒有提供合適接口的類。
(2)接口:想要使用接口中的某個或某些方法锦亦,但是接口中有太多方法舶替,我們要使用時必須實(shí)現(xiàn)接口并實(shí)現(xiàn)其中的所有方法令境,可以使用抽象類來實(shí)現(xiàn)接口杠园,并不對方法進(jìn)行實(shí)現(xiàn)(僅置空),然后我們再繼承這個抽象類來通過重寫想用的方法的方式來實(shí)現(xiàn)舔庶。這個抽象類就是適配器抛蚁。
2.代理模式
代理模式給某一個對象提供一個代理對象,并由代理對象控制對原對象的引用
在某些情況下惕橙,一個客戶類不想或者不能直接引用一個委托對象瞧甩,而代理類對象可以在客戶類和委托對象之間起到中介的作用,其特征是代理類和委托類實(shí)現(xiàn)相同的接口弥鹦。
包含以下角色:
ISubject:抽象接口肚逸。該接口是 真實(shí)對象 和它的 代理 共用的接口。
RealSubject:真實(shí)主題角色彬坏,是實(shí)現(xiàn)抽象主題接口的類朦促。
Proxy:代理角色,內(nèi)部含有對真實(shí)對象RealSubject的引用栓始,從而可以操作真實(shí)對象务冕。代理對象提供與真實(shí)對象相同的接口,以便在任何時刻都能代替真實(shí)對象幻赚。同時禀忆,代理對象可以在執(zhí)行真實(shí)對象操作時,附加其他的操作落恼,相當(dāng)于對真實(shí)對象進(jìn)行封裝箩退。
靜態(tài)代理
優(yōu)點(diǎn):可以做到在符合開閉原則的情況下對目標(biāo)對象進(jìn)行功能擴(kuò)展。
缺點(diǎn):我們得為每一個服務(wù)都得創(chuàng)建代理類佳谦,工作量太大戴涝,不易管理。同時接口一旦發(fā)生改變吠昭,代理類也得相應(yīng)修改喊括。
//以買房的中介過程為例
//Proxy:代理角色
package main.java.proxy.impl;
import main.java.proxy.BuyHouse;//中介服務(wù)接口
public class BuyHouseProxy implements BuyHouse {
private BuyHouse buyHouse;
public BuyHouseProxy(final BuyHouse buyHouse) { //主體(服務(wù))角色買房實(shí)現(xiàn)(需求)傳入
this.buyHouse = buyHouse;
}
@Override
public void buyHosue() { //中介自己的買房實(shí)現(xiàn)
System.out.println("買房前準(zhǔn)備");
buyHouse.buyHosue();
System.out.println("買房后裝修");
}
}
———————————————————————————————————————
三、行為型
1.觀察者模式
在對象之間定義了一對多的依賴矢棚,這樣一來郑什,當(dāng)一個對象改變狀態(tài),依賴它的對象(觀察者)會收到通知并自動更新
其實(shí)就是發(fā)布訂閱模式蒲肋,發(fā)布者發(fā)布信息蘑拯,訂閱者獲取信息钝满,訂閱了就能收到信息,沒訂閱就收不到信息申窘。
結(jié)構(gòu)圖:
上圖有以下角色:
抽象被觀察者角色:也就是一個抽象主題弯蚜,它把所有對觀察者對象的引用保存在一個集合中,每個主題都可以有任意數(shù)量的觀察者剃法。抽象主題提供一個接口碎捺,可以增加和刪除觀察者角色。一般用一個抽象類和接口來實(shí)現(xiàn)贷洲。
聲明了添加收厨、刪除、通知觀察者方法
public interface Observerable {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
抽象觀察者角色:為所有的具體觀察者定義一個接口优构,在得到主題通知時更新自己诵叁。
定義了一個update()方法,當(dāng)被觀察者調(diào)用notifyObservers()方法時钦椭,觀察者的update()方法會被回調(diào)拧额。
public interface Observer {
public void update(String message);
}
具體被觀察者角色:也就是一個具體的主題,在集體主題的內(nèi)部狀態(tài)改變時彪腔,所有登記過的觀察者發(fā)出通知侥锦。
對Observerable接口的三個方法進(jìn)行了具體實(shí)現(xiàn),同時有一個List集合漫仆,用以保存注冊的觀察者捎拯,等需要通知觀察者時,遍歷該集合即可盲厌。
//注意到這個List集合的泛型參數(shù)為Observer接口署照,設(shè)計原則:面向接口編程而不是面向?qū)崿F(xiàn)編程
private List<Observer> list;
private String message;
public WechatServer() { //使用微信公眾號訂閱的例子
list = new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer o) {
list.add(o);
}
@Override
public void removeObserver(Observer o) {
if(!list.isEmpty())
list.remove(o);
}
//遍歷
@Override
public void notifyObserver() { //對所有用戶進(jìn)行狀態(tài)更改, 這里是消息數(shù)+1
for(int i = 0; i < list.size(); i++) {
Observer oserver = list.get(i);
oserver.update(message);
}
}
public void setInfomation(String s) {
this.message = s;
System.out.println("微信服務(wù)更新消息: " + s);
//消息更新,通知所有觀察者
notifyObserver();
}
具體觀察者角色:實(shí)現(xiàn)抽象觀察者角色所需要的更新接口吗浩,一邊使本身的狀態(tài)與制圖的狀態(tài)相協(xié)調(diào)建芙。
實(shí)現(xiàn)更新方法供被觀察者調(diào)用
public class User implements Observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
public void read() {
System.out.println(name + " 收到推送消息: " + message);
}