大话设计模式(更新ing...)
目錄
單例模式:
簡(jiǎn)單工廠模式
工廠方法模式
抽象工廠模式
策略模式
觀察者模式
適配器模式
模板方法模式(模板模式)
裝飾者模式
靜態(tài)代理模式
動(dòng)態(tài)代理模式
責(zé)任鏈模式
享元模式
迭代器模式
單例模式:
方式一:拿去吧!
如果一個(gè)對(duì)象被new了多次,但無法保證每個(gè)對(duì)象都會(huì)被使用,這時(shí)候就會(huì)很浪費(fèi)空間,而且如果訪問量巨大,服務(wù)器也要承擔(dān)很大的壓力。出現(xiàn)這種情況,一些Java大神們當(dāng)然不會(huì)放任著不管,于是經(jīng)過一番潛心研究,就出現(xiàn)了一種新的獲得對(duì)象的方式——單例模式。
單例模式大概做的事情就是通過自己的設(shè)計(jì),讓當(dāng)前的這個(gè)類只能產(chǎn)生一個(gè)對(duì)象(但是根據(jù)特定情況以及自己對(duì)于這一塊的設(shè)計(jì),不能一刀切的都去用這個(gè)方法,比如一個(gè)person類,每個(gè)person都有自己不同的屬性,怎么能都用一個(gè)person來做事情呢)。
如果做?
構(gòu)造方法:前面我們?yōu)榱瞬荒茈S便創(chuàng)建當(dāng)前對(duì)象,已經(jīng)給構(gòu)造方法私有化,所以排除此方法。
代碼塊:代碼塊會(huì)在對(duì)象創(chuàng)建的時(shí)候就加載了,但是沒有返回值,同樣獲取不到對(duì)象,排除。
普通方法:這個(gè)似乎和構(gòu)造方法一樣了,每次調(diào)用這個(gè)方法同樣會(huì)創(chuàng)建一個(gè)對(duì)象出來,也無法做到對(duì)象時(shí)單例的。
屬性:?似乎只能使用屬性來new對(duì)象,然后通過方法來將對(duì)象傳遞。
? ? ? ????????? public Singleton single = new Singleton();
上面這個(gè)寫法很明顯是不對(duì)的,而且在做單例上面,似乎沒有任何存在的意義。
原因是啥呢?
首先,這樣寫上來就是一個(gè)StackOverflow Error。因?yàn)檫@是類里面的屬性,類加載以后會(huì)加載自己里面的屬性,方法等。但是當(dāng)加載這個(gè)屬性的時(shí)候,發(fā)現(xiàn)又new了一個(gè)自己,然后又去加載自己類,又遇到一個(gè)屬性里面new了一個(gè)自己。。。陷入死循環(huán)導(dǎo)致棧溢出。
解決方法:保證是一份就OK啦。 public static Singleton single = new Singleton();
有些朋友可能看出還有一個(gè)問題:就是這樣寫我豈不是用類名就可以隨便調(diào)用了,Singleton.single簡(jiǎn)直不要太簡(jiǎn)單。所以呢,為了讓我的獲取對(duì)象的方法更有存在感,必然是不能讓您調(diào)用的嗷。
較為標(biāo)準(zhǔn)的寫法:private static Singleton single = new Singleton();
好啦。屬性對(duì)象創(chuàng)建好了,我怎么給你呢--->通過方法獲得。 設(shè)計(jì)一個(gè)方法,將當(dāng)前唯一的對(duì)象返回出去。? ? ? ?
public static Singleton getInstance(){//注意:這里return的是single屬性中存儲(chǔ)對(duì)象的地址引用return single;}這種方式又叫做餓漢式,也就是:上來就創(chuàng)建一個(gè)對(duì)象,如同餓漢見到食物上來就吃。但是呢,這樣在整個(gè)系統(tǒng)執(zhí)行過程中,如果創(chuàng)建的對(duì)象不使用,就會(huì)一直占用著內(nèi)存,造成了內(nèi)存空間的浪費(fèi)。
方式二:不用,我就不做!
這種方式呢,又叫做懶漢式,就是你可以要,但是我未必會(huì)創(chuàng)建,等到你用的時(shí)候我再創(chuàng)建,這樣就很大程度上避免了內(nèi)存空間浪費(fèi)問題。寫法和餓漢式幾乎一致,代碼如下:
private Singleton(){} //我先不創(chuàng)建對(duì)象 private static Singleton single; public static Singleton getInstance(){//這個(gè)時(shí)候你要用了,但是我要看看是否真的沒有創(chuàng)建好的對(duì)象嗎,沒有我再給你if(single == null){single = new Singleton();}return single; }有利肯定有弊:這時(shí)候要考慮到線程的問題了,比如A和B兩個(gè)線程,同時(shí)需要這個(gè)對(duì)象,假如A先開辟了一塊空間single,A正準(zhǔn)備判斷對(duì)象是否為空,這個(gè)時(shí)候時(shí)間片輪轉(zhuǎn),到B了,B也開辟了一塊空間,然后A又創(chuàng)建了對(duì)象,但此時(shí)B判斷對(duì)象已經(jīng)不為空了,但是自己又開辟了一塊空間,就比較沖突。當(dāng)線程數(shù)更多的話,資源的爭(zhēng)奪就會(huì)更明顯。所以,請(qǐng)看下個(gè)分解。
方式三:我給鎖住,讓你搶我的東西!
在懶漢式的基礎(chǔ)上加一個(gè)鎖,就是我在用這個(gè)對(duì)象的時(shí)候,我要給他鎖住,你們誰也不能動(dòng),直到我用完。代碼實(shí)現(xiàn)如下:
private Singelton(){} private static Singleton single; //當(dāng)前線程使用的時(shí)候不允許其他線程操作 public synchronized static Singleton getInstance(){if(single == null){single = new Singleton();}return single; }有利有弊:這種整個(gè)方法的執(zhí)行過程中,不能有其他線程操作的方式,線程安全是解決了,萬一你用很久,誰等的起啊。
方式四:雙重判定!
就是將當(dāng)前的類模板鎖住,而不是鎖住整個(gè)對(duì)象,這樣其他線程進(jìn)來如果對(duì)象不是空的,就可以直接返回了,而不需要去等待加鎖的線程執(zhí)行完畢,這樣大大提高了執(zhí)行效率。實(shí)現(xiàn)如下:
private Singelton(){} private static Singleton single; public static Singleton getInstance(){//第一重判定,如果為空,加鎖,創(chuàng)建對(duì)象if(single == null){synchronized(Singleton.class){//第二重判定,如果為空 創(chuàng)建對(duì)象if(single == null){single = new Singleton();}}}return single; }有利有弊:這樣在解決了加鎖性能的問題的同時(shí),在JVM虛擬機(jī)中,在對(duì)象的開辟和賦值的過程中,可能會(huì)產(chǎn)生指令重排序。本來時(shí)1 ——> 2 ——> 3的順序,可能會(huì)變成 1 ——> 3 ——> 2。
方式五:大哥來了!
屬性上添加volatile,保證屬性在加載和賦值的過程中,不會(huì)被JVM指令重排序。代碼如下:
private Singleton single(){} private static volatile Singleton single; public static Singleton getInstance(){if(single == null){synchronized(Singleton.class){if(single == null){single = new Singleton();}}} }簡(jiǎn)單工廠模式
大家所熟知的有工廠方法模式、抽象工廠模式,那么簡(jiǎn)單工廠模式又是什么呢?簡(jiǎn)單工廠模式不能算作一個(gè)標(biāo)準(zhǔn)的設(shè)計(jì)模式,但是呢,在開發(fā)之中又挺常用的,那么就當(dāng)做一個(gè)熱身吧!
舉一個(gè)小案例:話說有一天晚上,博主突發(fā)餓疾,非要去附近的小作坊買一些關(guān)東煮吃吃。且附近幾家都有賣。那么問題來了,我新來的這個(gè)地方,還不熟悉,我還沒吃過這附近的關(guān)東煮呢,萬一關(guān)東煮里面有其他東西,出了問題,我找誰去呢??找我買東西的那家店?萬一人家無證經(jīng)營跑路了呢。所以為了安全起見,我需要看到人家的營業(yè)執(zhí)照才放心的買。那么這就要求這些小作坊需要被統(tǒng)一管理起來(頒發(fā)營業(yè)執(zhí)照,你這家店可以賣關(guān)東煮),或者說的貼切代碼一些(遵循一個(gè)規(guī)則)。
好,假設(shè)有三家小作坊店,為了方便理解,類名就用拼音了(其實(shí)是我不會(huì)英語)。那么:GuanDongZhu1.java? ? GuanDongZhu2.java? ? GuanDongZhu3.java。這是我附近的三家店?,F(xiàn)在我要給他們指定一個(gè)規(guī)則,允許他們賣關(guān)東煮。AcceptGuanDongZhu.java。既然是指定規(guī)則的類,我們就可以將它指定為借口或者父類。此例中將其指定為借口。那么三個(gè)小作坊店都實(shí)現(xiàn)這個(gè)借口里面的方法(賣關(guān)東煮)。代碼如下:
GuanDongZhu1.java
public class GuanDongZhu1 implements AcceptGuanDongZhu{@Overridepublic void sale() {System.out.println("GuanDongZhu1號(hào)店也售賣關(guān)東煮,博主快來吃啊");} }GuanDongZhu2.java
public class GuanDongZhu2 implements AcceptGuanDongZhu{@Overridepublic void sale() {System.out.println("GuanDongZhu2號(hào)店售賣關(guān)東煮,博主快來吃啊");} }GuanDongZhu3.java
public class GuanDongZhu3 implements AcceptGuanDongZhu{@Overridepublic void sale() {System.out.println("GuanDongZhu3號(hào)店關(guān)東煮最好吃,博主快來吃啊");} }AcceptGuanDongZhu.java
public interface AcceptGuanDongZhu {//售賣關(guān)東煮的接口方法(營業(yè)執(zhí)照) 默認(rèn)用 public abstract修飾void sale(); }TestMain.java
public static void main(String[] args) {//多態(tài)來創(chuàng)建子類對(duì)象AcceptGuanDongZhu sale = new GuanDongZhu1();sale.sale(); }好,營業(yè)執(zhí)照給了,小作坊也遵循了,但是!新的問題來了。用戶這樣用,是不是知道的太多了。首先,他知道了我的接口規(guī)則(實(shí)現(xiàn)了AcceptGuanDongZhu這個(gè)接口),其次,我具體的實(shí)現(xiàn)類也讓他知道了,這完全違背封裝隔離的思想啊。那么我就需要把用戶和店隔開,用戶可以看見我的實(shí)現(xiàn)規(guī)則,但是呢,我不能讓你知道我的具體實(shí)現(xiàn)類是哪個(gè),你可以通過傳參數(shù)的方式,告知我想去哪個(gè)店,我給你找。而中間這個(gè)隔離層呢,就是我們今天的重點(diǎn)了——Factory。就是你告訴我工廠,你要買關(guān)東煮了,如果你傳給我一個(gè)參數(shù)(店名),那我就把這個(gè)店給到你,不傳,我就隨便給你一個(gè)。按照這種封裝隔離的思想,把具體的實(shí)現(xiàn)類包裝起來。代碼實(shí)現(xiàn)如下:
GuanDongZhuFactory.java
//調(diào)用我工廠 我要給你返回一個(gè)店 你給我傳一個(gè)店名 或者不傳我就隨機(jī)給你一個(gè)public AcceptGuanDongZhu getGuanDongZhu(String name){//下面就簡(jiǎn)單做個(gè)判斷,重要的是思想if(!"".equals(name) && "GuanDongZhu1".equals(name)){return new GuanDongZhu1();}else if(!"".equals(name) && "GuanDongZhu2".equals(name)){return new GuanDongZhu2();}else if(!"".equals(name) && "GuanDongZhu3".equals(name)){return new GuanDongZhu3();}else{//啥也不傳,我給你選一個(gè)return new GuanDongZhu1();}}那么這時(shí)候用戶找店的方式就應(yīng)該變成:
TestMain.java
public static void main(String[] args) {//先創(chuàng)建工廠GuanDongZhuFactory factory = new GuanDongZhuFactory();AcceptGuanDongZhu sale = factory.getGuanDongZhu("GuanDongZhu1");sale.sale();}工廠方法模式
引子:為什么會(huì)有工廠方法模式?
在上面的簡(jiǎn)單工廠模式中,用戶通過創(chuàng)建工廠對(duì)象來獲取目標(biāo)對(duì)象(GuanDongZhu對(duì)象),那么由于關(guān)東煮不止一家,用戶肯定有自己想去的一家,在簡(jiǎn)單工廠模式中依靠傳參數(shù)來決定選擇哪一家,那這就意味著用戶需要了解參數(shù)的意義。而且啊,添加了參數(shù),我工廠處理的時(shí)候豈不是多了很多的判斷,如:下面就是簡(jiǎn)單工廠中的工廠要做的事情。
if(!"".equals(name) && "GuanDongZhu1".equals(name)){return new GuanDongZhu1();}else if(!"".equals(name) && "GuanDongZhu2".equals(name)){return new GuanDongZhu2();}else if(!"".equals(name) && "GuanDongZhu3".equals(name)){return new GuanDongZhu3();}else{//啥也不傳,我給你選一個(gè)return new GuanDongZhu1();}這樣,每新開一家店,大工廠就要多一個(gè)判斷,是不是挺麻煩啊??墒遣慌袛嗄?#xff0c;我又不知道該創(chuàng)建哪個(gè)具體的對(duì)象,唉,好煩,不干了!對(duì),不干了——無為而治。那怎么辦?這樣吧,你大工廠把自己的方法變成抽象的,然后我再找人去專門創(chuàng)建對(duì)象,但是呢,你大工廠要把我創(chuàng)建好的對(duì)象給人家用戶好吧。“好!”。OK,大工廠的獲取對(duì)象的方法變成抽象了,那類也就是抽象的了。創(chuàng)建對(duì)象的事,我再找人,小弟多。我給每一個(gè)關(guān)東煮店都配一個(gè)創(chuàng)建對(duì)象的小弟(小工廠),然后由大工廠去把這個(gè)小工廠找過來遞給用戶。部分代碼實(shí)現(xiàn)如下:
GuanDongZhuFactory.java? ?總工廠類
public abstract class GuanDongZhuFactory {//判斷太麻煩 不干了! 你再找小弟去創(chuàng)建對(duì)象吧,我只負(fù)責(zé)給你找小弟,然后送給用戶public abstract AcceptGuanDongZhu chooseGuanDongZhu();//為了不讓用戶知道 我大工廠又去找小工廠干活了 掩蓋住我懶惰的事實(shí)public AcceptGuanDongZhu getGuanDongZhu(){return chooseGuanDongZhu();} }GuanDongZhu1Factory.java? ?每個(gè)店的小工廠(負(fù)責(zé)創(chuàng)建對(duì)象)
public class GuanDongZhu1Factory extends GuanDongZhuFactory{//一號(hào)店的小弟 創(chuàng)建了一號(hào)店對(duì)象@Overridepublic AcceptGuanDongZhu chooseGuanDongZhu() {return new GuanDongZhu1();} }TestMain.java
public static void main(String[] args) {//大工廠拿著小工廠給創(chuàng)建好的對(duì)象 借花獻(xiàn)佛 送給了用戶 賣關(guān)東煮成功GuanDongZhuFactory factory = new GuanDongZhu1Factory();AcceptGuanDongZhu sale = factory.getGuanDongZhu();sale.sale();}給每一家店都分配一個(gè)小工廠,這個(gè)小工廠只創(chuàng)建這一家的對(duì)象,就省去了判斷的步驟,用戶直接創(chuàng)建對(duì)應(yīng)的那一家店,這樣只暴露給用戶工廠類,具體實(shí)現(xiàn)類用戶是不知道的。
所謂工廠方法,中的方法指的就是總工廠里面的抽象方法,小工廠通過繼承大工廠,然后重寫這個(gè)方法實(shí)現(xiàn)對(duì)象創(chuàng)建。 工廠方法模式中的 “ 方法 ”。
public abstract AcceptGuanDongZhu chooseGuanDongZhu();抽象工廠模式
模擬計(jì)算機(jī)組件(主板,CPU)來描述此模式,(相關(guān)知識(shí)可能有誤,見諒)先實(shí)現(xiàn)沒有抽象工廠模式,只是簡(jiǎn)單工廠模式,將兩者進(jìn)行對(duì)比。
簡(jiǎn)單工廠模式實(shí)現(xiàn)如下:
AMDCPU.java
public class AMDCPU implements CPU {//屬性 名字private String name;//CPU的管腳數(shù)private int basePins;public AMDCPU(String name, int basePins) {this.name = name;this.basePins = basePins;}//CPU用戶核心計(jì)算 實(shí)現(xiàn)一個(gè)接口 CPU 統(tǒng)一進(jìn)行計(jì)算@Overridepublic void centerCalculate() {System.out.println("這是AMD的CPU" + this.name);} } InterCPU.java public class InterCPU implements CPU{private String name;private int basePins;public InterCPU(String name,int basePins){this.name = name;this.basePins = basePins;}//CPU用戶核心計(jì)算 實(shí)現(xiàn)一個(gè)接口 進(jìn)行統(tǒng)一管理@Overridepublic void centerCalculate() {System.out.println("這是Inter的CPU" + this.name);} }CPU.java? 統(tǒng)一管理的接口
void centerCalculate();CPUFactory.java? 創(chuàng)建對(duì)象的簡(jiǎn)單工廠
//默認(rèn) 1 是 Inter 2 是 AMDpublic static CPU createCPU(int type){if(type == 1){return new InterCPU("Inter",1155);}else{return new AMDCPU("AMD",775);}}ASUSMainBoard.java??
private String name;//針對(duì)于CPU上面的管腳數(shù)private int CPUPins;public ASUSMainBoard(String name,int CPUPins){this.name = name;this.CPUPins = CPUPins;}//實(shí)現(xiàn)統(tǒng)一接口 安裝主板@Overridepublic void installMainBoard() {System.out.println("ASUS主板"+this.name+",CPU針腳數(shù)為:"+this.CPUPins);}MSIMainBoard.java
private String name;private int CPUPins;public MSIMainBoard(String name,int CPUPins){this.name = name;this.CPUPins = CPUPins;}//實(shí)現(xiàn)統(tǒng)一接口 安裝主板@Overridepublic void installMainBoard() {System.out.println("MSI主板:"+this.name+",CPU針腳數(shù)為:"+this.CPUPins);}MainBoard.java? 統(tǒng)一接口
void installMainBoard();MainBoardFactory.java? 創(chuàng)建對(duì)象的簡(jiǎn)單工廠類
//傳遞參數(shù):主板類型,默認(rèn) 1 是 MSI 2 是 ASUSpublic static MainBoard createMainBoard(int type){if(type == 1){return new MSIMainBoard("MSI",1155);}else{return new ASUSMainBoard("ASUS",775);}}TestMain.java
public static void main(String[] args){//用戶根據(jù)需求向工程師要求用什么樣的主板 什么樣的CPUComputerEngineer engineer = new ComputerEngineer();engineer.assembleComputer(1,2);}問題:這樣讓用戶來傳遞主板和CPU的參數(shù),可能會(huì)出現(xiàn)創(chuàng)建的對(duì)象和其他工廠的不匹配,比如創(chuàng)建了一個(gè)針腳為1155的主板,卻創(chuàng)建了針腳為775的CPU,這樣是不匹配的。而此時(shí),抽象工廠模式,是更注重一系列對(duì)象互相之間的依賴關(guān)系。類似于資源的整合,同樣針腳數(shù)的主板和CPU可以當(dāng)做一套來創(chuàng)建返回給用戶,這種方法的實(shí)現(xiàn)方式就是:使用一個(gè)抽象工廠來規(guī)定一套規(guī)則(主板和CPU),然后指定相應(yīng)個(gè)計(jì)劃,讓用戶來傳遞這個(gè)計(jì)劃給工程師(相當(dāng)于套餐),工程師組裝電腦給用戶。新增代碼如下:
AbastactFactory.java
public interface AbstractFactory {MainBoard mainBoard();CPU CPU(); }PlanA.java? ?裝機(jī)方案A
/*** 一套計(jì)劃————>實(shí)現(xiàn)抽象工廠類 為用戶提供一套可用計(jì)劃*/ public class PlanA implements AbstractFactory{@Overridepublic MainBoard mainBoard() {return new ASUSMainBoard("ASUS",1155);}@Overridepublic CPU CPU() {return new AMDCPU("AMD",1155);} }PlanB.java? 和A類似 不予贅述
ComputerEngineer.java??
//工程師根據(jù)用戶提供的計(jì)劃來組裝電腦public void assembleComputer(AbstractFactory plan){//創(chuàng)建主板和CPUMainBoard board = plan.mainBoard();CPU cpu = plan.CPU();board.installMainBoard();cpu.centerCalculate();}TestMain.java
public static void main(String[] args){//用戶只需要提供一個(gè)方案 工程師按照方案來組裝AbstractFactory plan = new PlanA();//找工程師ComputerEngineer engineer = new ComputerEngineer();engineer.assembleComputer(plan);}策略模式
舉個(gè)栗子:假設(shè),假設(shè)哈,博主我是一個(gè)房地產(chǎn)開發(fā)商(美死我了)。那么我要賣房子了??蛻魜碣I房子,我們實(shí)行的是有認(rèn)識(shí)的人可以打折的政策。假定用戶認(rèn)識(shí):售樓部門主管,或者是幫我蓋房子的工人,或者認(rèn)識(shí)我。假定用戶認(rèn)識(shí)他們就可以享受打折。否則就是普通用戶,無打折活動(dòng)。那么下面的類來實(shí)現(xiàn)這一關(guān)系,售房。用戶給一個(gè)指定價(jià)格來買對(duì)應(yīng)的房子。
Price.java? ?報(bào)價(jià)的類
//報(bào)價(jià)的類 public class Price {//該方法用來計(jì)算用戶買這個(gè)房的最終價(jià)格//參數(shù):用戶報(bào)價(jià) 和 是否具有享受活動(dòng)的關(guān)系(使用int類型來代表關(guān)系)//0 代表 蓋房子的工人 1 代表 售樓主管 2 代表 老板(我)//返回值:返回最終價(jià)格 由于買房涉及金額較大 直接使用int類型public int calculatePrice(int price,int identify){//判斷是哪種身份來進(jìn)行最終價(jià)格的計(jì)算switch(identify){case 0 :System.out.println("工人的親屬來買房啦,蓋房子辛苦了,打個(gè)大折吧");return price - 100000;case 1 :System.out.println("認(rèn)識(shí)我們售樓主管啊,多介紹親戚來買房啊,給便宜些");return price - 50000;case 2 :System.out.println("認(rèn)識(shí)老板啊,老板叫什么?看在老板面子上給你多便宜點(diǎn)吧");return price - 5;default:System.out.println("不是買房的啊,不能搗亂嗷");return price + 200000000;}} }直接new Price()對(duì)象調(diào)用方法即可。那么現(xiàn)在看這個(gè)實(shí)現(xiàn)方式,缺點(diǎn)是不是賊多。
首先:用戶就迷惑了,你給的這個(gè)identify是啥意思啊,我該傳個(gè)啥啊??不懂。。??勺x性不好
其次:看看這方法里面,又是判斷,又是計(jì)算的,累不累啊。。而且計(jì)算過程都暴露出來了,一點(diǎn)都不懂得保護(hù)隱私。。
好吧好吧。改寫-->
傳遞參數(shù)identify時(shí),可以換成一個(gè)靜態(tài)常量,或者枚舉也行。這樣可讀性會(huì)更好一些了。方法里面做的事情多呢,我就給他抽離出來唄,單獨(dú)做一個(gè)方法你去調(diào)用。請(qǐng)看下面修改版:
Type.java? 代表身份的類
public class Type {//靜態(tài)常量 表示身份public static final int WORKER_PRICE = 0;public static final int MANAGER_PRICE = 1;public static final int BOSS_PRICE = 2; }改版后的price.java
//改版一:將身份參數(shù)換成靜態(tài)常量 增加可讀性//一個(gè)方法做事情太多,將一些事情抽出來單獨(dú)形成一個(gè)方法public int calculatePrice(int price,int identify){int endPrice = 0;//判斷是哪種身份來進(jìn)行最終價(jià)格的計(jì)算switch(identify){case Type.WORKER_PRICE :endPrice = calculateForWorker(price);break;case Type.MANAGER_PRICE :endPrice = calculateForManager(price);break;case Type.BOSS_PRICE :endPrice = calculateForBoss(price);break;default:endPrice = calculateForDefault(price);break;}return endPrice;}//抽離出來用于計(jì)算價(jià)格的方法 參數(shù):用戶報(bào)價(jià) 返回值:返回計(jì)算出來的最終價(jià)格private int calculateForWorker(int price){System.out.println("工人的親屬來買房啦,蓋房子辛苦了,打個(gè)大折吧");return price - 100000;}private int calculateForManager(int price){System.out.println("認(rèn)識(shí)我們售樓主管啊,多介紹親戚來買房啊,給便宜些");return price - 50000;}private int calculateForBoss(int price){System.out.println("認(rèn)識(shí)老板啊,老板叫什么?看在老板面子上給你多便宜點(diǎn)吧");return price - 5;}private int calculateForDefault(int price){System.out.println("不是買房的啊,不能搗亂嗷");return price + 200000000;}好啦,身份可讀性增強(qiáng)了,計(jì)算方法也抽離出來了,還有什么可說的呢。當(dāng)然有!!(畢竟今天的主題還沒說呢是吧~.~)。先挑問題:目前是只有三個(gè)身份,倘若有一天有一百個(gè)身份,一萬個(gè)身份,去添這個(gè)case,讓誰添誰不得瘋啊。正式一點(diǎn)的用語就是違反了設(shè)計(jì)模式的開閉原則。擴(kuò)展性太差。這就引出了我們的策略模式。策略模式如果從代碼結(jié)構(gòu)上來分析就是將原有每一個(gè)單獨(dú)計(jì)算的方法從類中拆出去,升級(jí)成為單獨(dú)的類中的單獨(dú)方法(每一個(gè)方法獨(dú)立)。實(shí)現(xiàn)如下:
Stragegy.java? ?策略類接口? 子類實(shí)現(xiàn)此接口,遵循此策略
public interface Strategy {int calculatePrice(int price); }各子類策略的實(shí)現(xiàn)
WorkerStrategy.java
/*** 工人的策略類 專門計(jì)算工人的買房?jī)r(jià)格*/ public class WorkerStrategy implements Strategy{@Overridepublic int calculatePrice(int price) {System.out.println("工人的親屬來買房啦,蓋房子辛苦了,打個(gè)大折吧");return price - 100000;} }ManagerStrategy.java
/*** 售樓主管的策略類*/ public class ManagerStrategy implements Strategy{@Overridepublic int calculatePrice(int price) {System.out.println("認(rèn)識(shí)我們售樓主管啊,多介紹親戚來買房啊,給便宜些");return price - 50000;} }BossStrategy.java同上,不贅述。
Price.java:
//得到價(jià)格的方法//參數(shù):價(jià)格 父類的策略public int getPrice(int price,Strategy strategy){int endPrice = 0;endPrice = strategy.calculatePrice(price);return endPrice;}策略模式未來就是來解決這種流程固定,但是具體執(zhí)行有些差別的問題。
觀察者模式
舉個(gè)栗子:假設(shè)有一家甜品店。不定期推出新的甜品試吃活動(dòng)。有試吃活動(dòng)肯定會(huì)有試吃用戶,則用戶和甜品店之間就是 依賴關(guān)系(use - a:一個(gè)類中的一個(gè)方法使用到另一個(gè)類對(duì)象)甜品店需要有用戶來試吃? 。先來實(shí)現(xiàn)普通的甜品店和試吃用戶的類之間的關(guān)系。
DessertShop.java? 甜品店類
/*** 甜品店類*/ public class DessertShop {//屬性private String name;/*getter和setter方法省略*///出新品的方法 用戶來試吃//參數(shù):不需要//返回值:新甜品public Dessert newDessert(){System.out.println("新甜品出來啦,快來免費(fèi)試吃啊");Dessert dessert = new Dessert();dessert.setName("牛奶小新");return dessert;} }Dessert.java? 甜品類
/***甜品類*/ public class Dessert {private String name;/*getter和setter方法省略*/ }EatPerson1.java? 試吃員1號(hào)(不是吃人1號(hào)啊)
/*** 1號(hào)試吃員*/ public class EatPerson1 {private String name;public EatPerson1(String name){this.name = name;}//獲取新的甜品//參數(shù):甜品店 返回值:不需要public void eatNew(DessertShop shop){Dessert dessert = new Dessert();System.out.println("試吃了"+shop.getName()+"家的"+dessert.getName()+"甜品");} }TestMain.java
public class TestMain {public static void main(String[] args){//創(chuàng)建甜品店對(duì)象DessertShop shop = new DessertShop("1號(hào)甜品店");//創(chuàng)建試吃用戶EatPerson1 person1 = new EatPerson1("1號(hào)試吃員");//用戶主動(dòng)找到這個(gè)甜品店person1.eatNew(shop);} }好,那么我們看這個(gè)普通的類設(shè)計(jì)有什么問題呢,到底是什么樣的問題才能引入今天的主題來呢?
首先:現(xiàn)在只有一個(gè)對(duì)象,但是保不齊某一天甜品店爆火,試吃人數(shù)激增呢,還去創(chuàng)建這么些對(duì)象嗎??但是這個(gè)問題目前是無法解決的,但是在后期Spring的IOC就可以來做到了,所以這里暫時(shí)不去他做專門的處理。
其次:每次試吃讓客戶自己主動(dòng),這樣對(duì)象一多,做的事情就多了,是不是不太好啊,而且,我不要面子的嘛!!
好,遇到問題,解決問題。引出今天的主題-->觀察者模式。誰觀察?? 大家想一下公眾號(hào)。是不是公眾號(hào)只要有新文章就會(huì)推送給用戶啊,那么我們用戶就充當(dāng)了一個(gè)觀察者的角色,來監(jiān)聽著甜品店的動(dòng)向,什么時(shí)候出新品,我要吃熱乎的!!!
好,那我們來改變一下類的設(shè)計(jì):這個(gè)時(shí)候就要從依賴關(guān)系變成了 has - a的聚合關(guān)系。甜品店中存儲(chǔ)了很多用戶,來監(jiān)聽著甜品店的動(dòng)向。
基本流程:
? ? ? ? 1. 目標(biāo)對(duì)象中存儲(chǔ)這很多觀察者
? ? ? ? ? ? ? ? ? ? ? ? 一個(gè)屬性,集合,里面存儲(chǔ)這很多的觀察者
? ? ? ? 2.設(shè)計(jì)一個(gè)方法
? ? ? ? ? ? ? ? ? ? ? ? 往集合中添加/刪除觀察者
? ? ? ? 3.甜品店做事情
? ? ? ? 4.甜品店通知每一位用戶來試吃甜品
代碼實(shí)現(xiàn)如下:
EatPerson.java? ?試吃員統(tǒng)一接口
/*** 試吃員統(tǒng)一接口*/ public interface EatPerson {void eatNew(DessertShop shop); }EatPerson1.java? ?EatPerson2.java? ?EatPerson3.java? 都實(shí)現(xiàn)此接口,代碼未做改變。
DessertShop.java? 改版后的甜品店類
/*** 甜品店類*/ public class DessertShop {//屬性private String name;/*getter 和 setter方法省略*///=====新版本===================================================//需要一個(gè)集合來存儲(chǔ)所有的觀察者//觀察者需要一個(gè)統(tǒng)一的規(guī)范,來當(dāng)做我存儲(chǔ)的泛型類 接口//為什么使用ArrayList??因?yàn)檫@個(gè)集合遍歷操作使用的比較多private List<EatPerson> observers = new ArrayList<>();//將觀察者放入到集合中public void add(EatPerson person){observers.add(person);}//可能會(huì)移除觀察者public void remove(EatPerson person){observers.remove(person);}//通知所有的觀察者public void notity(){for(EatPerson p : observers){p.eatNew(this);}}//=====舊版本==================================================//出新品的方法 用戶來試吃//參數(shù):不需要//返回值:新甜品public void newDessert(){System.out.println("新甜品出來啦,快來免費(fèi)試吃啊");Dessert dessert = new Dessert();dessert.setName("牛奶小新");//通知每個(gè)觀察者this.notity();} }TestMain.java? 測(cè)試方法
public static void main(String[] args){//===新版本========================================//創(chuàng)建甜品店對(duì)象DessertShop shop = new DessertShop("1號(hào)甜品店");//創(chuàng)建客戶對(duì)象EatPerson1 person1 = new EatPerson1("1號(hào)試吃員");EatPerson2 person2 = new EatPerson2("2號(hào)試吃員");EatPerson3 person3 = new EatPerson3("3號(hào)試吃員");//甜品店主動(dòng) 找客戶//將客戶裝到觀察者集合中shop.add(person1);shop.add(person2);shop.add(person3);//找用戶試吃shop.newDessert();}以上便是觀察者模式。
適配器模式
適配器模式可將其劃分為三類(也就是此文中要介紹的三種):
? ? ? ? 1.對(duì)象適配器
? ? ? ? 2.類適配器
? ? ? ? 3.缺省適配器
先來介紹對(duì)象適配器。為了更加貼合,就使用電腦上面的存儲(chǔ)卡(SD)卡來當(dāng)做此模式的示例來實(shí)現(xiàn)吧。我們先來介紹對(duì)象適配器。
眾所周知,存儲(chǔ)卡是分為大卡和小卡的,電腦使用的就是正常大卡,我們的電腦上面也僅僅只留了一個(gè)接口用來插存儲(chǔ)卡,那我要是想使用小卡插入到電腦中該怎么辦呢?自己拿錐子開辟一個(gè)接口??那電腦鑿成什么樣子了。小玩笑(一點(diǎn)也不好笑)。相比同志們也都見過卡套吧,一個(gè)小卡外面套著一個(gè)大卡模型的模樣(將自己打扮成大人模樣是吧)。外面那一層是沒有芯片的,只是充當(dāng)一個(gè)模具來將小卡送到卡槽中。那這樣一個(gè)卡套就是我們今天要說的“對(duì)象適配器”了。詳情見如下代碼實(shí)現(xiàn):
對(duì)象適配器
假定以金士頓品牌的SD卡來當(dāng)做案例。分為大卡,小卡
MiniSDCard.java? 小卡統(tǒng)一接口
/*** 小卡統(tǒng)一接口*/ public interface MiniSDCard {public void read();public void write(); }SDCard.java? 大卡統(tǒng)一接口
/*** 存儲(chǔ)卡統(tǒng)一讀寫數(shù)據(jù)的接口*/ public interface SDCard {public void read();public void write(); }KingstonMiniSDCard.java? ?金士頓小SD卡
/*** 金士頓牌子的小卡* 實(shí)現(xiàn)統(tǒng)一存儲(chǔ)卡小卡接口*/ public class KingstonMiniSDCard implements MiniSDCard {//讀取和寫入的功能public void read(){System.out.println("小卡的讀取功能");}public void write(){System.out.println("小卡的寫入功能");} }KingstonSDCard.java? 金士頓大SD卡? 和小卡實(shí)現(xiàn)一致? 不贅述
CoverForMiniSDCard.java? ?小卡卡套
/*** 小卡的卡套 將小卡包到卡套里面之后就是一個(gè)大卡 所以實(shí)現(xiàn)統(tǒng)一大卡接口*/ public class CoverForMiniSDCard implements SDCard {//卡套和小卡的關(guān)系??//卡套和小卡形成了一個(gè)整體 沒有卡套 小卡沒法使用 沒有小卡 卡套只是一個(gè)塑料//所以二者在類上是has - a的包含關(guān)系private MiniSDCard miniSDCard;public CoverForMiniSDCard(MiniSDCard miniSDCard){this.miniSDCard = miniSDCard;}//在讀取和寫入數(shù)據(jù)的時(shí)候 當(dāng)然使用小卡來操作 因?yàn)樾酒谛】ɡ锩? 卡套只是一個(gè)工具@Overridepublic void read() {this.miniSDCard.read();}@Overridepublic void write() {this.miniSDCard.write();} }Computer.java? 插卡的電腦
/*** 插存儲(chǔ)卡的電腦*/ public class Computer {//電腦的讀取和寫入//參數(shù):給電腦一張卡 只需要傳遞統(tǒng)一大卡接口 因?yàn)樾】ㄒ呀?jīng)使用卡套變成了大卡樣子public void readAndWrite(SDCard sdCard){sdCard.read();sdCard.write();} }TestMain.java? 對(duì)象適配器測(cè)試類
public static void main(String[] args){//先需要一個(gè)電腦Computer computer = new Computer();//需要一張大卡 本來的大卡可以使用 所以只需要操作小卡//小卡需要卡套 所以先new小卡 有了小卡 傳遞給卡套 形成了大卡 傳遞給電腦 讀取和寫入數(shù)據(jù)成功MiniSDCard mini = new KingstonMiniSDCard();CoverForMiniSDCard cover = new CoverForMiniSDCard(mini);computer.readAndWrite(cover);}類適配器
假設(shè)有一種小卡,是可以折疊的,展開是一張大卡,一半是芯片,另一個(gè)半是塑料。我們?cè)儆眠@樣一種卡來實(shí)現(xiàn)匹配類適配器。
新增類
SpecialSDCardForMini.java? 折疊小卡? 展開是一張大卡 內(nèi)含芯片
/*** 可以折疊的一種小卡* 首先,他是金士頓的一種卡 extends 體現(xiàn)是一個(gè)* 其次,他需要當(dāng)做大卡使用 遵循統(tǒng)一大卡的規(guī)則*/ public class SpecialSDCardForMini extends KingstonMiniSDCard implements SDCard {@Overridepublic void read() {this.readMini();}@Overridepublic void write() {this.writeMini();} }TestMain.java? ?
public static void main(String[] args){//先要有一個(gè)電腦Computer computer = new Computer();//需要一張可折疊的卡SDCard card = new SpecialSDCardForMini();computer.readAndWrite(card);}其他類無變化。僅添加了折疊卡類和去除了對(duì)于卡套的使用。
實(shí)際底層就是對(duì)于小卡變成大卡的適配實(shí)現(xiàn)。
缺省適配器
缺省適配器就是相當(dāng)于電腦上面的一個(gè)擴(kuò)展塢,由擴(kuò)展塢直接和電腦連接,其他的實(shí)現(xiàn)類去和擴(kuò)展塢連接就可以(在擴(kuò)展塢中選擇自己需要的方法,進(jìn)行方法重寫)。
USBCard.java? 缺省適配器抽象類,自身實(shí)現(xiàn)了大卡和小卡的接口,具有通用的方法,用戶可以在其中選擇需要的方法進(jìn)行重寫
/*** 抽象類 擴(kuò)展塢*/ public abstract class USBCard implements MiniSDCard, SDCard {@Overridepublic void readMini(){System.out.println("小卡的讀功能");}@Overridepublic void writeMini(){System.out.println("小卡的寫功能");}@Overridepublic void read(){System.out.println("大卡的讀功能");}@Overridepublic void write(){System.out.println("大卡的寫功能");} } KingstonSDCard.java 大卡繼承拓展塢 /*** 金士頓牌子的正???電腦使用的大卡)* 繼承拓展塢類 重寫需要的方法*/ public class KingstonSDCard extends USBCard {//有讀取功能public void read(){System.out.println("大卡讀取");}//有寫入的功能public void write(){System.out.println("大卡寫入");} }KingstonMiniCard.java? 小卡繼承拓展塢
/*** 金士頓牌子的小卡* 繼承拓展塢類 實(shí)現(xiàn)需要的方法*/ public class KingstonMiniSDCard extends USBCard {//讀取和寫入的功能public void readMini(){System.out.println("小卡的讀取功能");}public void writeMini(){System.out.println("小卡的寫入功能");} }以上就是適配器模式的三種情況。
模板方法模式(模板模式)
話不多說,上來就干!我們今天來做一個(gè)小登錄(玩點(diǎn)小高級(jí)的東西)。通過實(shí)現(xiàn)這個(gè)登錄方法來引出我們今天的主題--模板方法模式。既然是登錄嘛,主題是設(shè)計(jì)模式,所以一切從簡(jiǎn),數(shù)據(jù)庫啥的就不寫了,直接來個(gè)簡(jiǎn)易版。那也就是一個(gè)實(shí)體類(存儲(chǔ)用戶名密碼),一個(gè)普通用戶類,一個(gè)管理員類,一個(gè)測(cè)試類。齊活。等等,代碼附在后面。
AdminUser.java? ?存儲(chǔ)管理員用戶名和密碼的實(shí)體類
private String username; private String password; /*其余略。。。*/NormalUser.java? 存儲(chǔ)普通用戶的用戶名和密碼類
private String username; private String password; /*其余略。。。*/AdminUserLogin.java 管理員的登錄方法
//管理員登錄方法public String adminLogin(String username,String password){//假裝從dao中查詢admin的信息AdminUser admin = this.selectOne(username);//獲取加密的密碼String encryptPass = this.encryptPassword(password);if(admin != null && encryptPass.equals(admin.getPassword())){return "登錄成功";}return "登錄失敗,用戶名或密碼錯(cuò)誤";}//dao查詢admin的信息public AdminUser selectOne(String username){AdminUser admin = new AdminUser("Java","666");//給管理員的密碼加個(gè)密 后存入到"數(shù)據(jù)庫"中this.encryptPassword(admin.getPassword());return admin;}//加密方法 給管理員的密碼加密public String encryptPassword(String password){System.out.println("給管理員的密碼加密了");return password;}NormalUserLogin.java? 普通用戶的登錄方法
//普通用戶登錄方法public String normalLogin(String username,String password){//調(diào)用dao方法(假裝)通過username查詢信息 判斷是否登錄成功NormalUser user = this.selectOne(username);if(!user.equals(null) && password.equals(user.getPassword())){return "登錄成功";}return "登錄失敗,用戶名或密碼錯(cuò)誤";}//假裝從數(shù)據(jù)庫中查詢信息的daopublic NormalUser selectOne(String username){//先來一個(gè)NormalUserNormalUser user = new NormalUser("炸雞","123");return user;}好啦。這樣我們定睛一看!問題這不就來了嘛。這樣每一個(gè)用戶,這樣來看僅僅是一個(gè)類就搞定了信息的存儲(chǔ),但是如果放到數(shù)據(jù)庫中,這可就是一個(gè)表啊,一個(gè)管理員一個(gè)用戶這就兩張表了。而且這兩個(gè)類的方法都類似,登錄方法,實(shí)體類都是一致的。是否可以將這兩個(gè)合并到一起呢。當(dāng)然。這也就是今天的模板方法模式的主場(chǎng)了。請(qǐng)看以下操作。
User.java? 普通用戶和管理員共用的實(shí)體類
private String username;private String password;//好 我們假設(shè)用戶又多了一個(gè)屬性 age 管理員在賦值的時(shí)候可直接賦值為空private Integer age;LoginTemplate.java? ?登錄模板抽象類 子類繼承去實(shí)現(xiàn)登錄等一些登錄相關(guān)操作
/*** 將用戶和管理員相同的方法都放到這個(gè)抽象類里面 來當(dāng)做一個(gè)模板* 因?yàn)槌橄箢愂窃试S有非抽象方法 和 抽象方法的* 所以 保不齊有方法兩者都需要 且 操作不同 那么這個(gè)方法就當(dāng)做必須重寫的方法定義到這個(gè)類里面*/ public abstract class LoginTemplate {//方法一:登錄驗(yàn)證流程 這個(gè)就當(dāng)做是一個(gè)統(tǒng)一的 不需要重寫//同時(shí) 我們也默認(rèn)這個(gè)方法是不允許子類去重寫的 因?yàn)檫@個(gè)流程我已經(jīng)規(guī)定好了 你不用改//所以我要用final來修飾這個(gè)方法 以防子類去重寫來打亂我執(zhí)行的流程public final String login(String username,String password){//調(diào)用管理員和普通用戶各自的查詢信息的方法 去獲取對(duì)象信息User user = this.selectOne(username);//但是管理員的密碼是有一個(gè)加密需求的 所以需要規(guī)定一個(gè)密碼加密方法 但是不是必須重寫的 因?yàn)槠胀ㄓ脩舨恍枰猄tring encryptPass = this.encryptPassword(password);//判斷密碼是否正確if(user != null && password.equals(encryptPass)){return "登錄成功";}return "登錄失敗,用戶名或密碼錯(cuò)誤";}//查詢對(duì)象信息驗(yàn)證登錄是否正確//雖然這個(gè)方法兩個(gè)類都需要 但是流程又不一樣 那么好,我做一個(gè)定義 你去自己重寫好了//這個(gè)方法我只允許子類實(shí)現(xiàn) 但是用public修飾時(shí),在同包中都是可見的 所以需要將其保護(hù)起來protected abstract User selectOne(String username);//密碼加密方法 不是必須重寫 誰需要誰重寫protected String encryptPassword(String password){//這個(gè)方法在這里面什么也不做 等著子類去重寫return password;} }AdminLogin.java? 管理員登錄
/*** 管理員登錄 繼承抽象模板方法 重寫查詢方法 和 密碼加密方法*/ public class AdminLogin extends LoginTemplate{@Overridepublic User selectOne(String username) {User user = new User();user.setUsername("炸雞");user.setPassword("123");return user;}@Overrideprotected String encryptPassword(String password) {System.out.println("密碼加密咯");return password;}}NormalLogin.java? 普通用戶登錄
? /*** 普通用戶登錄 繼承模板方法 實(shí)現(xiàn)查詢方法 不需要實(shí)現(xiàn)加密方法*/ public class NormalLogin extends LoginTemplate{@Overridepublic User selectOne(String username) {User user = new User();user.setUsername("Java");user.setPassword("666");return user;} }好啦。這就是模板模式啦,您覺得怎樣呢
裝飾者模式
首先。舉個(gè)栗子,假設(shè)現(xiàn)在有一個(gè)賣房子的團(tuán)隊(duì),那我們實(shí)現(xiàn)一下關(guān)于他們工資發(fā)放的流程吧(簡(jiǎn)單的流程,因?yàn)槲乙膊欢唧w是怎么發(fā)放)。該團(tuán)隊(duì)肯定有普通職員,工作年限為半年,假設(shè)其銷售額度為4000,每個(gè)月績(jī)效提成為3%;另有一位普通職員,工作年限為3年,假設(shè)其銷售額度為6000,每個(gè)月績(jī)效提成為3%,銷售額度每大于5000再在其基礎(chǔ)上漲幅1%;還有團(tuán)隊(duì)負(fù)責(zé)人(主管),假設(shè)其銷售為7000,每個(gè)月績(jī)效提成為3%,但是還會(huì)提取超過銷售額度超過5000的1%,以及團(tuán)隊(duì)總額的1%。下面是普通的實(shí)現(xiàn),不含設(shè)計(jì)模式。
User.java? 描述職員信息
//姓名private String name;//工資private double salary;//身份 普通/主管private String identity;UserBox.java? ?替代數(shù)據(jù)庫,存儲(chǔ)職員信息
public class UserBox {//使用一個(gè)map集合private static HashMap<String,User> userBox = new HashMap<>();static{userBox.put("Ming",new User("小明",4000,"普通"));userBox.put("Gang",new User("小剛",6000,"普通"));userBox.put("Hong",new User("小紅",7000,"主管"));}//設(shè)計(jì)一個(gè)方法 獲取集合public static HashMap<String,User> getUserBox(){return userBox;}//設(shè)計(jì)一個(gè)方法 通過名字獲取對(duì)應(yīng)的人信息public static User getUser(String user){return userBox.get(user);} }CalcBonus.java? 計(jì)算績(jī)效獎(jiǎng)金
public class CalcBonus {//通過給定的名字 來計(jì)算其對(duì)應(yīng)的獎(jiǎng)金public double calcBonus(String name){double sum = 0;//分別找三個(gè)小弟 對(duì)三種獎(jiǎng)金制度進(jìn)行分別的計(jì)算//操作一:計(jì)算基礎(chǔ)獎(jiǎng)金sum += baseBonus(name);//操作二:計(jì)算銷售額大于5000的獎(jiǎng)金sum += beyondBonus(name);//操作三:計(jì)算主管要提取的sum += extraBonus(name);return sum;}//小弟一:計(jì)算基礎(chǔ)獎(jiǎng)金private double baseBonus(String name){User user = UserBox.getUser(name);double sum = 0;sum = user.getSalary() * 0.03;return sum;}//小弟二:計(jì)算銷售額大于5000的獎(jiǎng)金private double beyondBonus(String name){User user = UserBox.getUser(name);double sum = 0;double salary = user.getSalary();if(salary >= 5000){sum = salary * 0.01;}return sum;}//小弟三:計(jì)算主管提取的獎(jiǎng)金private double extraBonus(String name){double sum = 0;//查看當(dāng)前name是否為主管if("主管".equals(name)){// 遍歷所有職員double all = 0;for(String key : UserBox.getUserBox().keySet()){//將所有職員的工資加起來 然后乘以0.01 就是主管要提取的團(tuán)隊(duì)獎(jiǎng)金all += UserBox.getUser(key).getSalary();}//提取sum = all * 0.01;}return sum;} }這是普通的不帶有設(shè)計(jì)模式的一個(gè)實(shí)現(xiàn)方式,缺點(diǎn)是很明顯的--->可擴(kuò)展性極差,也就是說如果我可能在某一天改變獎(jiǎng)金策略,或者不發(fā)獎(jiǎng)金,這樣修改起來就很麻煩,而且如果我要新增一個(gè)獎(jiǎng)金政策,還需要去CaluBonus類中新增一個(gè)方法去計(jì)算對(duì)應(yīng)的計(jì)算策略,那萬一我已經(jīng)將項(xiàng)目打包呢,是否又違反了開閉原則。there is problem,there is slove(塑料英語,別介意)。裝飾者模式來咯。我們可以把裝飾者模式想象成買煎餅的場(chǎng)面。首先肯定是一張餅躺在那,上面才能"裝飾"火腿腸啊,雞柳啊,生菜啊等等的。那我們來簡(jiǎn)單的實(shí)現(xiàn)一下。(每個(gè)步驟會(huì)在代碼中有較為詳細(xì)的注釋)。
從表層到底層的次序來展示代碼:
Bonus.java? 基礎(chǔ)的獎(jiǎng)金類
/*** 最基礎(chǔ)的計(jì)算獎(jiǎng)金的類 相當(dāng)于煎餅中的一個(gè)餅*/ /*** 將每個(gè)裝飾者都實(shí)現(xiàn)了Decorator抽象類 那么現(xiàn)在 我當(dāng)前這個(gè)類和Decorator又是什么關(guān)系呢,* 現(xiàn)在是我寫的方法名一致 可能知道他們是計(jì)算獎(jiǎng)金的 但是如果方法不一致呢,而且用戶也不知道啊* 那不如再來一個(gè)超級(jí)父類 將他倆綁定到一起 產(chǎn)生一個(gè)裝飾關(guān)系 用接口定義一個(gè)規(guī)則 用戶用起來也方便 SuperBonus.java*/ public class Bonus implements SuperBonus{//設(shè)計(jì)一個(gè)方法 用來計(jì)算獎(jiǎng)金public double calcuBonus(String name){//老板心情不好 獎(jiǎng)金全部取消!! 好了,這個(gè)方法沒有獎(jiǎng)金而言System.out.println("默認(rèn)沒有獎(jiǎng)金");double num = 0;return num;} }MonthBonus.java? 裝飾者1 月度基本獎(jiǎng)金
/*** 每個(gè)月的基本的0.03獎(jiǎng)金* 在Bonus之后 獲取該類的獎(jiǎng)金* 相當(dāng)于煎餅中的一個(gè)火腿腸-->是額外加的*/ public class MonthBonus extends Decorator{//直接繼承裝飾者類private Decorator d;public MonthBonus(Decorator d){this.d = d;} // private Bonus bonus;public double calcuBonus(String name){//先獲得bonusdouble sum = d.calcuBonus(name);//計(jì)算自己的sum += UserBox.getUser(name).getSalary() * 0.03;return sum;} }BeyondBonus.java? 裝飾者2? 銷售額超額獎(jiǎng)金
/*** 銷售額度超過5000塊的1%的提成(裝飾者1)* 會(huì)在Bonus之后才有 先有基礎(chǔ)的 再有外加的* 相當(dāng)于煎餅中的雞柳-->額外的*/ public class BeyondBonus extends Decorator{//直接繼承裝飾者對(duì)象 // private Bonus bonus; // private MonthBonus bonus;private Decorator d;public BeyondBonus(Decorator d){this.d = d;}public double calcuBonus(String name){//先獲得基礎(chǔ)的獎(jiǎng)金(管你有沒有,先要再說)double sum = d.calcuBonus(name);//計(jì)算我自己辛苦得來的那1%獎(jiǎng)金sum += UserBox.getUser(name).getSalary() * 0.01;return sum;} }ExtraBonus.java? 裝飾者3??主管提取獎(jiǎng)金
/*** 主管提取全部職員的總額的1%的獎(jiǎng)金類* 前提是:我先要基礎(chǔ)的 再要銷售額大于5000的那1% 再計(jì)算我自己的* 相當(dāng)于煎餅中的 雞排-->額外的*/ public class ExtraBonus extends Decorator{private Decorator d;//構(gòu)造方法 創(chuàng)建對(duì)象public ExtraBonus(Decorator d){this.d = d;}//既然都是裝飾者 何不如歸為一個(gè)類下-->繼承抽象類 Decorator // private Bonus bonus; // private BeyondBonus beyond;public double calcuBonus(String name){//基礎(chǔ)獎(jiǎng)金double sum = d.calcuBonus(name);//5000塊的1%提成sum += d.calcuBonus(name);//計(jì)算我自己的總額1%//遍歷mapdouble all = 0;for(String key : UserBox.getUserBox().keySet()){all += UserBox.getUser(key).getSalary();}sum += all * 0.01;return sum;} }Decorator.java? 抽象類? 規(guī)定裝飾者的模板
/*** 裝飾者的父類 規(guī)定一個(gè)裝飾者的模板* 實(shí)現(xiàn)統(tǒng)一計(jì)算獎(jiǎng)金的接口 統(tǒng)一方法名*/ public abstract class Decorator implements SuperBonus{//計(jì)算獎(jiǎng)金的抽象方法public abstract double calcuBonus(String name); }SuperBonus.java? ?接口 統(tǒng)一Bonus和Decorator方法名
/*** 聲明Bonus和Decorator的關(guān)系 讓計(jì)算獎(jiǎng)金的方法名統(tǒng)一 用戶用起來較為方便*/ public interface SuperBonus {public double calcuBonus(String name); }裝飾者模式到此結(jié)束~~
靜態(tài)代理模式
同樣的,舉個(gè)栗子先。今天我們來舉關(guān)于手機(jī)的例子。手機(jī),當(dāng)前要工廠了,假設(shè),假設(shè)一下,現(xiàn)在的手機(jī)售賣店都是前面是門店,后面是工廠,當(dāng)然,工廠是隱藏起來的。就舉iPhone的例子吧,一個(gè)手機(jī)店配著一個(gè)工廠,那么手機(jī)店和工廠就是use-a的依賴關(guān)系啦。好,那我們開始實(shí)現(xiàn)。老樣子,先實(shí)現(xiàn)最基礎(chǔ)的類和類的關(guān)系,然后一點(diǎn)點(diǎn)增加,直到形成設(shè)計(jì)模式。
iPhone.java? 描述手機(jī)
/*** 這個(gè)類是用來描述手機(jī)的*/ public class iPhone {private String name;private String color;/*構(gòu)造方法略*///手機(jī)的一些功能public void game(){System.out.println("蘋果手機(jī)打游戲反應(yīng)快");}public void call(){System.out.println("蘋果手機(jī)打電話流暢");}public void photo(){System.out.println("蘋果手機(jī)拍照清晰");} }AppleStore.java? 手機(jī)店(包含工廠)
/*** 這個(gè)類是蘋果手機(jī)的專賣店 可以理解為他的工廠*/ private class AppleStore {//這個(gè)手機(jī)店因?yàn)閹е粋€(gè)工廠 所以他可以生產(chǎn)手機(jī)和賣手機(jī)public iPhone productPhone(){iPhone phone = new iPhone("iPhone11","white");System.out.println("生產(chǎn)一臺(tái)手機(jī)");return phone;}public iPhone salePhone(){iPhone phone = this.productPhone();System.out.println("售賣手機(jī)");return phone;} }測(cè)試方法直接創(chuàng)建手機(jī)店,賣手機(jī)即可,這里不在描述。
那現(xiàn)在有這么一個(gè)情況,人們都知道這個(gè)手機(jī)好賣,那么就有商人也想賣這種牌子的手機(jī),于是申請(qǐng)為代理商(這個(gè)代理賣真機(jī)的過程不再描述,重點(diǎn)在后面),代理商賣了一段時(shí)間之后,用戶信譽(yù)已經(jīng)養(yǎng)成差不多了,開始覺得里面似乎有利可圖,可以將采購回來的真機(jī)里面的零部件換上那么一兩個(gè),反正一般的客戶也看不出來。這樣的事情愈演愈烈,終于有一天,整部手機(jī)都變成了假的。當(dāng)全部都變成假的了的時(shí)候,還有必要從人家那里拿貨自己再去處理嗎,那也太麻煩了,有那時(shí)間早就自己造一個(gè)工廠了。對(duì)!自己來一個(gè)山寨工廠,造山寨手機(jī)。然后拿來當(dāng)做真機(jī)賣。但是用戶不知道啊,還以為代理商賣的是真手機(jī),還來這買,殊不知已經(jīng)被偷偷地?fù)Q過了。
經(jīng)過一番收拾,把代理商門店裝修的本店一模一樣,連客服都穿一樣的衣服,然后再將手機(jī)變成和真機(jī)一樣的外觀,一樣的功能方法。用戶在購買的時(shí)候就無法分清楚所拿到的是真手機(jī)還是假手機(jī)。
ProxyStore.java? 代理商
/*** 代理商 實(shí)現(xiàn)Store接口 裝修風(fēng)格和真手機(jī)店一模一樣 并且要一樣的賣手機(jī)的方式和客服*/ public class ProxyStore implements Store{//代理商全部賣假手機(jī) 自己造一個(gè)山寨工廠 生成rPhoneprivate rPhone productPhone(){rPhone phone = new rPhone("rPhone11","white");return phone;}//售賣rPhone@Overridepublic rPhone salePhone(){//也可以售賣真手機(jī) 這個(gè)可以根據(jù)自己設(shè)計(jì)來選擇(遇到漂亮的小姐姐就賣假的,制造售后機(jī)會(huì))rPhone phone = this.productPhone();System.out.println("賣假手機(jī)咯");return phone;} }rPhone.java? 假手機(jī)
/*** 用來描述假手機(jī) 仿真iPhone 和真iphone有一樣的功能*/ public class rPhone implements Phone{private String name;private String color;public rPhone(String name,String color){this.name = name;this.color = color;}public void call(){System.out.println("假iPhone,打電話,你說什么,我聽不清");}public void game(){System.out.println("假iPhone,打游戲,閃退");}public void photo(){System.out.println("假iPhone,拍照,自動(dòng)打碼");} }Phone.java? ?統(tǒng)一手機(jī)接口 長得一樣 功能方法也一樣
/*** 統(tǒng)一手機(jī)接口 長得一樣 功能一樣*/ public interface Phone {public void game();public void photo();public void call(); }Store.java
/*** 統(tǒng)一手機(jī)店的裝修風(fēng)格 看不出來真假 實(shí)現(xiàn)一個(gè)賣手機(jī)的方法 連客服都一樣*/ public interface Store {public Phone salePhone(); }靜態(tài)代理模式一般在進(jìn)行架構(gòu)的時(shí)候可能會(huì)使用上,因?yàn)檫@樣在需要更換一些已實(shí)現(xiàn)的功能或底層架構(gòu)的時(shí)候不會(huì)對(duì)使用者造成影響。(偷偷地)
動(dòng)態(tài)代理模式
這次要介紹的動(dòng)態(tài)代理模式就以靜態(tài)代理模式例子為基礎(chǔ)來講吧,這樣比較好理解一些。代碼實(shí)現(xiàn)依然保持靜態(tài)代理的形式,保留了:Store.class,iPhone.class,AppleStore.class三個(gè)類,只是排除了靜態(tài)代理里面的代理商。這次的代理商我不想自己去創(chuàng)建了,我想讓別人創(chuàng)建好給我,我只需要拿著這個(gè)創(chuàng)建好的代理對(duì)象去賣手機(jī)即可。那么我這個(gè)“別人”應(yīng)該是誰呢,很明顯,就是一個(gè)工廠嘛,就是我這個(gè)手機(jī)的代工廠,我把手機(jī)的規(guī)格,各種配置啥的給你,你按照這個(gè)要求去生產(chǎn),然后給我,我拿去賣,這樣多好啊。
StoreFactory.java? ?代理工廠類? 幫我做手機(jī)
/*** 這個(gè)類就相當(dāng)于是一個(gè)代工廠 用來創(chuàng)建實(shí)例對(duì)象 做一些這個(gè)對(duì)象應(yīng)該做的事情,返回出去一個(gè)用戶需要的結(jié)果*/ public class StoreFactory {//可能會(huì)有不同的人來找我做事(我做的事情肯定不是單一的生成iPhone手機(jī),肯定還能干其他事情)//所以對(duì)于不同的用戶調(diào)用可能要返回不同的代理對(duì)象 泛型//參數(shù)呢? 用戶給我一個(gè)需要代理的對(duì)象(給我一個(gè)需要去代理的對(duì)象)public static <T>T getInstance(Class clazz){//創(chuàng)建代理類的對(duì)象是java提供的工具方法//參數(shù):三個(gè)參數(shù)://1.類加載器 把需要代理的這個(gè)對(duì)象加載進(jìn)來ClassLoader loader = clazz.getClassLoader();//2.代理誰 將要代理的對(duì)象包成一個(gè)數(shù)組傳遞Class[] classes = new Class[]{clazz};//3.代理之后我需要做什么事情InvocationHandler handler = new InvocationHandler() {@Override//這個(gè)方法就是代理這個(gè)對(duì)象之后我改做什么事情public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("我是代工廠,我要生產(chǎn)手機(jī)了");iPhone phone = new iPhone("iPhone11","white");return phone;}};T proxy = (T) Proxy.newProxyInstance(loader, classes,handler);//將這個(gè)代理的對(duì)象返回出去return proxy;} }由于事情都交給了代理工廠來做,AppleStore只是規(guī)定代理工廠要做什么,所以將其抽象成為一個(gè)接口。
AppleStore.java?
/*** 這個(gè)類是蘋果手機(jī)的專賣店 可以理解為他的工廠 實(shí)現(xiàn)統(tǒng)一手機(jī)店接口*/ public interface AppleStore extends Store {@Overridepublic iPhone salePhone() ; }測(cè)試類? 通過代理工廠來獲得手機(jī)對(duì)象并售賣出去
public static void main(String[] args) {//找代理工廠 來幫我生產(chǎn)手機(jī) 我要賣手機(jī)啦//但是在這個(gè)AppleStore里面 除了一個(gè)賣手機(jī)的方法之外已經(jīng)不做任何其他事情了 事情都交給了代理工廠來做//所以需要將其抽象為一個(gè)接口 (只需要告訴代工廠你這個(gè)手機(jī)的型號(hào)之類的信息即可)AppleStore store = StoreFactory.getInstance(AppleStore.class);iPhone phone = store.salePhone();//使用手機(jī)phone.call();phone.game();phone.game(); }以上就是動(dòng)態(tài)代理模式了,我自己對(duì)于動(dòng)態(tài)代理的理解就是,對(duì)于代理對(duì)象的動(dòng)態(tài),對(duì)于不能的代理對(duì)象會(huì)做不同的事情,而不是只能賣手機(jī),就像是一個(gè)代工廠,不一定只能做一個(gè)產(chǎn)品。誰來找我做我可以干的事情,我都干。就是這樣一個(gè)動(dòng)態(tài)的實(shí)現(xiàn)。
責(zé)任鏈模式
責(zé)任鏈模式在比較多的領(lǐng)域中如tomcat,Spring等中都有使用。個(gè)人覺得理解起來還是比較簡(jiǎn)單的。同樣的,例子先行。由于和鏈相關(guān),那咱就用鏈表來引出這個(gè)模式的問題。LinkedList想必大家都知道。我找你,你找他嘛(山有木兮木有枝~.~)。由于大家可能對(duì)于鏈表比較熟悉了,這里就不做代碼實(shí)現(xiàn)了。我們只用鏈表來引出責(zé)任鏈模式要解決的問題。大家都知道,鏈表是有頭結(jié)點(diǎn)的。那么為了便于理解,我們暫且把這個(gè)頭結(jié)點(diǎn)比作是一位老師,后面的其他結(jié)點(diǎn)都是一班里面的同學(xué)。然后這個(gè)連接的過程我們把他比作老師喊同學(xué)回答問題的過程(怎么樣,很形象吧)。那么放在鏈表上這樣的關(guān)系就是,老師先找一個(gè)學(xué)生,然后學(xué)生再找下一個(gè)學(xué)生??雌饋砗孟裢玫?#xff0c;老師只需要找一次,剩下的同學(xué)都會(huì)自動(dòng)去回答。但是呢,這樣下來,每次提問問題都這樣,那坐在后排的同學(xué)豈不是太爽了,因?yàn)橛谐渥愕臅r(shí)間去思考這個(gè)問題,但這似乎違背了老師想傳授的一個(gè)對(duì)于知識(shí)快速做出反應(yīng)的能力。所以這問題也就很明顯了。那么我們只好讓老師一個(gè)一個(gè)的去找學(xué)生了,那么老師找了一個(gè)學(xué)生之后,什么時(shí)候開始找下一個(gè)學(xué)生呢?——>當(dāng)前這個(gè)同學(xué)回答完畢之后給老師一個(gè)反饋,老師得到這個(gè)反饋之后,繼續(xù)找下一個(gè)同學(xué)。大家看這個(gè)方法是不是很好呢。那么這也就是責(zé)任鏈模式了。下面是代碼實(shí)現(xiàn)以及較為詳細(xì)的注釋講解。
ApplicationChain.java? ?相當(dāng)于教師類
/*** 這個(gè)類好比是老師 用來找同學(xué)回答問題*/ public class ApplicationChain {//記錄當(dāng)前提問到哪個(gè)同學(xué)(保證不能重復(fù))private int counts = 0;//老師這個(gè)班級(jí)里面肯定要有學(xué)生啊//用一個(gè)集合 來存儲(chǔ)所有的學(xué)生private ArrayList<Node> nodes = new ArrayList<>();//提供一個(gè)方法 將學(xué)生交給老師管理public void addNode(Node node){nodes.add(node);}//老師喊同學(xué)回答問題//同學(xué)在哪?? 集合里面public void doFilter(){//從集合里隨機(jī)獲取一個(gè) 暫不考慮越界的問題(主要是設(shè)計(jì)模式)Node node = nodes.get(counts++);//找同學(xué)回答問題node.doFilter(this);} }Node.java? 相當(dāng)于學(xué)生類
/*** 這個(gè)類好比是每個(gè)同學(xué) 在一個(gè)班級(jí)里面*/ public class Node {//學(xué)生的屬性private int id;public Node(int id){this.id = id;}//回答問題的方法//給誰回答呢?老師//那這個(gè)老師我從哪獲得呢?//屬性? 學(xué)生有一個(gè)老師?不合適吧//傳參? 每個(gè)同學(xué)有一個(gè)老師?多個(gè)同學(xué)可以對(duì)應(yīng)同一個(gè)老師 可以public void doFilter(ApplicationChain chain){//回答問題System.out.println(this.id+"號(hào)同學(xué)回答問題");//問題回答完畢了 干什么??//告訴老師 我回答完了,你可以找下一個(gè)同學(xué)了 我自己不需要知道下一個(gè)是誰//我自己?jiǎn)栴}回答對(duì)了,自己偷著樂,回答錯(cuò)了反省去,別管下一個(gè)是誰//找老師chain.doFilter();} }TestMain.java? 測(cè)試類
public static void main(String[] args) {//創(chuàng)建學(xué)生類Node node1 = new Node(1);Node node2 = new Node(2);Node node3 = new Node(3);//創(chuàng)建老師類ApplicationChain chain = new ApplicationChain();//將學(xué)生交給老師管理chain.addNode(node1);chain.addNode(node2);chain.addNode(node3);//找學(xué)生回答問題chain.doFilter();}以上就是責(zé)任鏈模式了,個(gè)人覺得理解起來還是比較簡(jiǎn)單的。
享元模式
所謂享元模式:享-->共享? ? 元-->單元(對(duì)象) ,是一種結(jié)構(gòu)型的設(shè)計(jì)模式,主要就是為了減少對(duì)象的創(chuàng)建(和單例模式是有區(qū)別的)。
同樣的,我們用一個(gè)例子來引出需要介紹的內(nèi)容。就舉一個(gè)學(xué)生去圖書館借書的例子吧。那么在這個(gè)例子的基礎(chǔ)上,會(huì)產(chǎn)生出三個(gè)對(duì)象:圖書館、書、學(xué)生。圖書館里面有書,學(xué)生可以使用圖書館來實(shí)現(xiàn)借書操作。圖書館默認(rèn)每個(gè)學(xué)校只有一個(gè),所以需要將其變成一份(單例的)。
最簡(jiǎn)單的享元模型:圖書館中的每一類書都只有一本,每次學(xué)生來借這個(gè)書,都會(huì)創(chuàng)建一個(gè)新的當(dāng)前書對(duì)象(相當(dāng)于圖書館會(huì)每次買一本新的這一類的書),但是考慮到學(xué)生會(huì)歸還書籍的,當(dāng)所有的書都?xì)w還回來極有可能導(dǎo)致圖書館放不下。那么就考慮到在圖書館中引入書柜,將同一名字的書多放幾本,然后供多個(gè)學(xué)生循環(huán)使用。
改版后的享元模型:圖書館中引入了書柜(一個(gè)集合,用來存儲(chǔ)同一名字的書籍),將同一名字的書存多份,并在初始化時(shí)為每一本書設(shè)置一個(gè)借閱狀態(tài)(boolean),這樣同學(xué)們就可以共享這幾本書,而不至于每次都去買新的。這就達(dá)到了對(duì)象的共享,而不是每次都去創(chuàng)建新的。學(xué)生每次取圖書館借書,圖書館為學(xué)生發(fā)放對(duì)應(yīng)的書籍(或是人工,或是自動(dòng)),而不是學(xué)生自己去取,也就將將書對(duì)象隱藏到圖書館里面,學(xué)生是看不到的,所以圖書館從書柜拿書的過程學(xué)生也是不知道的,學(xué)生只負(fù)責(zé)拿到書去看,看完歸還,剩下的操作都是圖書館來做的。
享元模式整體的思想也就是:盡量少的去減少同一類型對(duì)象的創(chuàng)建,能復(fù)用盡量復(fù)用,從而減少內(nèi)存空間的浪費(fèi),同單例模式不同,單例模式是將對(duì)象變成一份的,大家共享;而享元模式是將對(duì)象變成多份大家輪詢共享。
(以上享元模式的總結(jié)為本人學(xué)習(xí)之后的個(gè)人理解)
迭代器模式
這里的迭代器模式是和java.util.Iterator對(duì)象是一樣的。就是在遍歷時(shí)有一個(gè)統(tǒng)一的規(guī)則,方便于遍歷操作。這里假設(shè)有一個(gè)餐館,專門用來做快餐,有自己的服務(wù)員,有自己的菜單。在某一天,這家餐館里面入駐了一家蛋糕店。這家蛋糕店也有自己的菜單,但是由于店面太小,沒有服務(wù)員,就把請(qǐng)服務(wù)員的錢給到快餐店,讓快餐店來 幫忙售賣自己家的產(chǎn)品。那么這個(gè)時(shí)候服務(wù)員就需要每來一位顧客就要拿著兩個(gè)菜單給顧客點(diǎn)菜。這樣對(duì)于服務(wù)員來說是很麻煩的。所以我們希望有一個(gè)統(tǒng)一的規(guī)則來將這兩個(gè)菜單合并到一起(將所有的菜提供給顧客,自己選擇)。這就需要要求兩家店面都實(shí)現(xiàn)一個(gè)接口(自定義的 Iteraotor)。這樣每個(gè)店面在初始化的時(shí)候?qū)⒉藛螛?gòu)造出來,然后將其放入到一個(gè)菜單集合中,當(dāng)兩個(gè)門店都這樣做了之后,我兩個(gè)門店的菜單就交到迭代器手上了。然后服務(wù)員通過獲取兩個(gè)門店的迭代器對(duì)象(菜單),開始自己的遍歷,將所有菜單全部展示出來。
以下是代碼實(shí)現(xiàn):
Iterator.java? ?自定義的迭代器統(tǒng)一規(guī)則
boolean hasNext(); Object next();MenuItem.java? 描述菜品
private String name;//名稱private String description;//菜品描述private double price;//價(jià)格Restaurant.java? ?快餐店 用于初始化菜單
public DinerMenu() {menuItems = new MenuItem[MAX_ITEMS];//4個(gè)長度//這里面添加本店的菜品}//為了讓服務(wù)員點(diǎn)菜方便 將菜單全部拿走public MenuItem[] getMenuItems() {return menuItems;}//提供一個(gè)獲取迭代器對(duì)象的集合public Iterator createIterator(){return new DinerMenuIterator(menuItems);}RestaurantInterator.java? 實(shí)現(xiàn)迭代器規(guī)則的快餐店
public class RestaurantInteratorimplements Iterator{private MenuItem[] items;private int position = 0;//迭代位置public RestaurantInterator(MenuItem[] items) {this.items = items;}public boolean hasNext() {if(position >= items.length || items[position] == null) {return false;}else {return true;}}public Object next() {MenuItem menuItem = items[position++];return menuItem;} }Cake.java? 入駐的蛋糕店,實(shí)現(xiàn)方式和餐館一致,不贅述
Waiter.java? ?服務(wù)員類 獲取兩個(gè)門店的迭代器對(duì)象,遍歷兩個(gè)店的菜單
public void printMenu(){//獲取兩個(gè)迭代器對(duì)象Iterator cit = cake.createIterator();Iterator rit = restaurant.createIterator();//讓小弟幫我們迭代this.myprint(cit);this.myprint(rit);}//設(shè)計(jì)一個(gè)小弟方法 迭代private void myprint(Iterator iterator){while(iterator.hasNext()){MenuItem menuItem = (MenuItem) iterator.next();System.out.print(menuItem.getName()+", ");System.out.print(menuItem.getPrice()+", ");System.out.println(menuItem.getDescription());}}創(chuàng)作不易,辛苦點(diǎn)個(gè)贊吧~~
總結(jié)
以上是生活随笔為你收集整理的大话设计模式(更新ing...)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于springdatajpa 注解@C
- 下一篇: 设计模式前言