設計模式 重點版(常用10個)


創建型(創建對象): 2 個 (工廠模式, 單例模式)

結構型: 6 個 (適配器模式, 組合模式, 裝飾者模式, 代理模式, 外觀模式, 橋梁模式)

行為型: 8 個 (中介者模式, 策略模式, 模板模式, 觀察者模式, 迭代器模式, 責任鏈模式, 命令模式, 狀態模式)

 

1. 工廠模式

提供一個創建類的統一接口.

目的: 每次創建類時, 只需要調用這個接口就可以了, 不用每次都需要寫一次創建代碼

 

上面是簡單的工廠模式, 正常的工廠方法模式, 就是針對每個類, 都要創建一個工廠類. 但是他們可以實現共同的接口. (這種模式映射了之前我看的object c 的那本書), 一般用簡單的工廠模式就可以了.

2. 單例模式

保證在內存中一個類只有一個實例存在, 並且提供一個訪問該實例的全局訪問點.

目的: 例如一個系統中可能存在多個打印任務, 但是只能一個正在工作的打印任務在內存中.

 

 

 

餓漢式: 類加載時, 就創建好了這個單例( 很餓, 所以要立刻吃, 立刻加載)

 

懶加載(懶漢式):  可以用的時候再加載 (吃的時候再說, 不是一開始就把飯做好)

如果 getInstance() 使用頻率很高, 那肯定是餓漢式好.

 

 

 

 

 

利用 反射 破解單例模式

 

 

實際上, 在構造器函數內, 加一句話就可以防止反射破解單例

if (instance != null) {

  throw new RuntimeException();    // 也就是多次多用構造器時, 拋出異常

通過反序列化的方式 構造多個對象, 破解單例

首先,通過序列化把對象寫到硬盤上, 然后在把這個對象反序列化讀回到程序中, 這時就不是之前的對象了.

 

如何防止序列化, 通過定義一個 readResolve() 方法 , 這個方法的作用是,在反序列化時, 如果這個類已經定義了實例, 直接返回這個實例就可以了, 不需要new一個新的了.

 

 

3. 適配器模式

將一個類的接口轉換成客戶希望的另一個接口.

目的: 比如我們去別的地方, 我們的插座的方向頭是不一樣的, 比如(中國, 德國 我出差去德國), 適配器需要滿足以下要求:

(1) 必須符合德國標准的接口,否則的話還是沒辦法插到德國插座中

(2) 在調用上面實現的德標接口進行充電時,提供一種機制,將這個調用轉到對國標接口的調用

這就要求:

(1) 適配器必須實現原有的舊的接口

(2) 適配器對象中持有對新接口的引用,當調用舊接口時,將這個調用委托給實現新接口的對象來處理,也就是在適配器對象中組合一個新接口

image

 

4. 組合模式

將對象組合成樹型結構以表示“部分---整體”的層次結構

image

組合模式類似 “樹”

component: 組合中對象的接口聲明

composite: 樹枝結點(有子節點)

leaf: 樹葉結點(無子節點)

目的: 就是你想要這種層次關系的類時, 就可以使用.

例如: 各部門之間的層級關系

 

抽象接口類:
 
package com.zyh.designpattern.composite;
 
public abstract class Company {
 
private String name;
 
public Company(String name) {
 
super();
 
this.name = name;
 
}
 
public Company(){}
 
public String getName() {
 
return name;
 
}
 
public void setName(String name) {
 
this.name = name;
 
}
 
protected abstract void add(Company company);
 
protected abstract void romove(Company company);
 
protected abstract void display(int depth);
 
}
 
枝結點類:
 
package com.zyh.designpattern.composite;
 
import java.util.ArrayList;
 
import java.util.List;
 
public class ConcreteCompany extends Company {
 
private List cList; public ConcreteCompany() { cList = new ArrayList(); } public ConcreteCompany(String name) { super(name); cList = new ArrayList(); } @Override
 
protected void add(Company company) {
 
// TODO Auto-generated method stub
 
cList.add(company);
 
}
 
@Override
 
protected void display(int depth) {
 
// TODO Auto-generated method stub
 
StringBuilder sb = new StringBuilder("");
 
for (int i = 0; i < depth; i++) {
 
sb.append("-");
 
}
 
System.out.println(new String(sb) + this.getName());
 
for (Company c : cList) {
 
c.display(depth + 2);
 
}
 
}
 
@Override
 
protected void romove(Company company) {
 
// TODO Auto-generated method stub
 
cList.remove(company);
 
}
 
}
 
兩個葉結點類:
 
-------------------------1---------------------------.
 
package com.zyh.designpattern.composite;
 
public class HRDepartment extends Company {
 
public HRDepartment(String name) {
 
super(name);
 
}
 
@Override
 
protected void add(Company company) {
 
}
 
@Override
 
protected void display(int depth) {
 
// TODO Auto-generated method stub
 
StringBuilder sb = new StringBuilder("");
 
for (int i = 0; i < depth; i++) {
 
sb.append("-");
 
}
 
System.out.println(new String(sb) + this.getName());
 
}
 
@Override
 
protected void romove(Company company) {
 
}
 
}
 
----------------2-------------------
 
package com.zyh.designpattern.composite;
 
public class FinanceDepartment extends Company {
 
public FinanceDepartment(String name) {
 
super(name);
 
}
 
@Override
 
protected void add(Company company) {
 
}
 
@Override
 
protected void display(int depth) {
 
// TODO Auto-generated method stub
 
StringBuilder sb = new StringBuilder("");
 
for (int i = 0; i < depth; i++) {
 
sb.append("-");
 
}
 
System.out.println(new String(sb) + this.getName());
 
}
 
@Override
 
protected void romove(Company company) {
 
}
 
}
 
客戶端:
 
package com.zyh.designpattern.composite;
 
public class Client {
 
public static void main(String[] args) {
 
// TODO Auto-generated method stub
 
Company root = new ConcreteCompany();
 
root.setName("北京總公司");
 
root.add(new HRDepartment("總公司人力資源部"));
 
root.add(new FinanceDepartment("總公司財務部"));
 
Company shandongCom = new ConcreteCompany("山東分公司");
 
shandongCom.add(new HRDepartment("山東分公司人力資源部"));
 
shandongCom.add(new FinanceDepartment("山東分公司賬務部"));
 
Company zaozhuangCom = new ConcreteCompany("棗庄辦事處");
 
zaozhuangCom.add(new FinanceDepartment("棗庄辦事處財務部"));
 
zaozhuangCom.add(new HRDepartment("棗庄辦事處人力資源部"));
 
Company jinanCom = new ConcreteCompany("濟南辦事處");
 
jinanCom.add(new FinanceDepartment("濟南辦事處財務部"));
 
jinanCom.add(new HRDepartment("濟南辦事處人力資源部"));
 
shandongCom.add(jinanCom);
 
shandongCom.add(zaozhuangCom);
 
Company huadongCom = new ConcreteCompany("上海華東分公司");
 
huadongCom.add(new HRDepartment("上海華東分公司人力資源部"));
 
huadongCom.add(new FinanceDepartment("上海華東分公司賬務部"));
 
Company hangzhouCom = new ConcreteCompany("杭州辦事處");
 
hangzhouCom.add(new FinanceDepartment("杭州辦事處財務部"));
 
hangzhouCom.add(new HRDepartment("杭州辦事處人力資源部"));
 
Company nanjingCom = new ConcreteCompany("南京辦事處");
 
nanjingCom.add(new FinanceDepartment("南京辦事處財務部"));
 
nanjingCom.add(new HRDepartment("南京辦事處人力資源部"));
 
huadongCom.add(hangzhouCom);
 
huadongCom.add(nanjingCom);
 
root.add(shandongCom);
 
root.add(huadongCom);
 
root.display(0);
 
}
 
}
各部門之間層級關系

 

5. 裝飾者模式

動態的給一個對象添加一些額外的職責

目的: 需要擴展一個類的功能, 或給一個類增加額外的功能, 例如: 比如生日蛋糕, 有一些級別的蛋糕的情況, 比如, 巧克力蛋糕, 草莓蛋糕等, 但是, 要想在蛋糕上單獨加一些東西, 比如加一些花, 等等, 這樣, 就可以將基本的蛋糕采用繼承關系, 而裝飾者有個抽象類, 那些加的花啊什么的, 都是繼承這個裝飾者類, 參考下邊類圖

image

 

6. 代理模式

為其他對象提供一種代理以控制對這個對象的訪問

目的: 對對象訪問進行控制, 比如西門慶找潘金蓮,那潘金蓮不好意思答復呀,咋辦,找那個王婆做代理,表現在程序上時是這樣的體現的

代碼如下:

package com.yangguangfu.proxy;
/**
 * 
 * @author 阿福(trygf521@126.com)<br>
 *定義一種類型的女人,王婆和潘金蓮都屬於這個類型的女人
 */
public interface KindWoman {
    
    //這種女人能做什么事情呢?
    public void makeEyesWithMan();//拋媚眼
    
    public void happyWithMan();//和男人那個....

}
一種類型嘛,那肯定是接口,定義個潘金蓮
package com.yangguangfu.proxy;
/**
 * 
 * @author 阿福(trygf521@126.com)<br>
 *定義一個潘金蓮是什么樣的人
 */
public class PanJinLian  implements KindWoman{

    @Override
    public void happyWithMan() {
        System.out.println("潘金蓮和男人在做那個...");
        
    }

    @Override
    public void makeEyesWithMan() {
        System.out.println("潘金蓮拋媚眼...");
        
    }

}
再定義個丑陋的王婆
package com.yangguangfu.proxy;
/**
 * 
 * @author 阿福(trygf521@126.com)<br>
 *王婆這個人老聰明了,她太老了,是個男人都看不上她,
 *但是她有智慧經驗呀,他作為一類女人的代理!
 */
public class WangPo implements KindWoman {
    
    private KindWoman kindWoman;
    
    public WangPo(){
        //默認的話是潘金蓮的代理
        this.kindWoman = new PanJinLian();
    }
    //她可以是KindWomam的任何一個女人的代理,只要你是這一類型
    public WangPo(KindWoman kindWoman){
        this.kindWoman = kindWoman;
    }

    @Override
    public void happyWithMan() {
        //自己老了,干不了了,但可以叫年輕的代替。
        this.kindWoman.happyWithMan();
        
    }

    @Override
    public void makeEyesWithMan() {
        //王婆年紀大了,誰看她拋媚眼啊
        this.kindWoman.makeEyesWithMan();
        
    }

}
兩個女主角都上場了,該男主角了,定義個西門慶
package com.yangguangfu.proxy;
/**
 * 
 * @author 阿福(trygf521@126.com)<br>
 *水滸傳是這樣寫的:西門慶被潘金蓮用竹竿敲了一下,西門慶看痴迷了,被王婆看到了,就開始撮合兩人好事,王婆作為潘金蓮的代理人收了不少好處費,那我們假設一下:
 *如果沒有王婆在中間牽線,這兩個不要臉的能成事嗎?難說得很!
 */
public class XiMenQiang {

    /**
     * @param args
     */
    public static void main(String[] args) {
        WangPo wangPo;
        //把王婆叫出來
         wangPo = new WangPo();
        //然后西門慶說,我要和潘金蓮Happy,然后王婆就安排了西門慶丟筷子哪出戲:
        wangPo.makeEyesWithMan();
        //看到沒有表面是王婆在做,其實爽的是潘金蓮
        wangPo.happyWithMan();
        
        

    }

}

image

 

7. 外觀模式

為子系統中的一組接口提供一個一致的界面

比如: 不知道大家有沒有比較過自己泡茶和去茶館喝茶的區別,如果是自己泡茶需要自行准備茶葉、茶具和開水,如圖1(A)所示,而去茶館喝茶,最簡單的方式就是跟茶館服務員說想要一杯什么樣的茶,是鐵觀音、碧螺春還是西湖龍井?正因為茶館有服務員,顧客無須直接和茶葉、茶具、開水等交互,整個泡茶過程由服務員來完成,顧客只需與服務員交互即可,整個過程非常簡單省事,如圖1(B)所示

image

在軟件開發中,有時候為了完成一項較為復雜的功能,一個客戶類需要和多個業務類交互,而這些需要交互的業務類經常會作為一個整體出現,由於涉及到的類比較多,導致使用時代碼較為復雜,此時,特別需要一個類似服務員一樣的角色,由它來負責和多個業務類進行交互,而客戶類只需與該類交互。外觀模式通過引入一個新的外觀類(Facade)來實現該功能,外觀類充當了軟件系統中的“服務員”,它為多個業務類的調用提供了一個統一的入口,簡化了類與類之間的交互。在外觀模式中,那些需要交互的業務類被稱為子系統(Subsystem)。如果沒有外觀類,那么每個客戶類需要和多個子系統之間進行復雜的交互,系統的耦合度將很大,如圖2(A)所示;而引入外觀類之后,客戶類只需要直接與外觀類交互,客戶類與子系統之間原有的復雜引用關系由外觀類來實現,從而降低了系統的耦合度,如圖2(B)所示。

image

image

 

8. 橋梁模式

橋梁模式將抽象部分與它的實現部分分離

image

目的: 比如我們有一個畫圖程序 有2個圖形(Circle Rectangle )和2種畫圖方法(Drawing1 Drawing2)圖形可能會使用Drawing1來畫圖 也可能使用Drawing2來畫圖在這個畫圖程序中有兩個可變因素 一個是圖形的種類 有可能會增加新的圖形 另一個是畫圖方法 可能會有Drawing3出現.

 

9. 中介者模式

中介者模式用一個中介對象封裝一系列的對象交互

目的: 比如 在生活中,當電腦缺少了一塊主板,那會怎么樣?如果有人這樣問我的話,我就會馬上跳出來說“這電腦肯定報廢了”,當然這不是重點。假如少了主板電腦還可以用的話,想想,里面的CPU、顯卡、聲卡、光驅、硬盤等等,不是就要我們自己用線把它們連起來。想想就覺得頭疼,那么現在你覺得主板在電腦里扮演着什么角色呢?

例2:

imageimage

image
Mediator:中介者接口。在里面定義了各個同事之間相互交互所需要的方法,可以是公共的方法,如Change方法,也可以是小范圍的交互方法

ConcreteMediator:具體的中介者實現對象。它需要了解並為維護每個同事對象,並負責具體的協調各個同事對象的交互關系。

Colleague:同事類的定義,通常實現成為抽象類,主要負責約束同事對象的類型,並實現一些具體同事類之間的公共功能,比如,每個具體同事類都應該知道中介者對象,也就是每個同事對象都會持有中介者對象的引用,這個功能可定義在這個類中。

ConcreteColleague:具體的同事類,實現自己的業務,需要與其他同事對象交互時,就通知中介對象,中介對象會負責后續的交互。

 

10. 策略模式

策略模式定義一系列的算法,把它們一個個封裝起來,並且使它們可以相互替換

比如:

劉備要到江東娶老婆了,走之前諸葛亮給趙雲(伴郎)三個錦囊妙計,說是按天機拆開能解決棘手問題,嘿,還別說,真解決了大問題,搞到最后是周瑜陪了夫人又折兵,那咱們先看看這個場景是什么樣子的。

先說說這個場景中的要素:三個妙計,一個錦囊,一個趙雲,妙計是亮哥給的,妙計放在錦囊里,俗稱就是錦囊妙計嘛,那趙雲就是一個干活的人,從錦囊取出妙計,執行,然后獲勝。用java程序怎么表現這些呢?

那我們先來看看圖

image

三個妙計是同一類型的東西,那咱就寫個接口:

package com.yangguangfu.strategy;
/**
 * 
 * @author trygf521@126.com:阿福
 * 首先定義一個策略接口,這是諸葛亮老人家給趙雲的三個錦囊妙計的接口。
 */
public interface IStrategy {
    //每個錦囊妙計都是一個可執行的算法。
    public void operate();

}

然后再寫三個實現類,有三個妙計嘛:

妙計一:初到吳國:

package com.yangguangfu.strategy;
/**
 * 
 * @author trygf521@126.com:阿福
 * 找喬國老幫忙,使孫權不能殺劉備。
 */
public class BackDoor implements IStrategy {

    @Override
    public void operate() {
        System.out.println("找喬國老幫忙,讓吳國太給孫權施加壓力,使孫權不能殺劉備...");
    }

}

妙計二:求吳國太開個綠燈,放行:

package com.yangguangfu.strategy;
/**
 * 
 * @author trygf521@126.com:阿福
 * 求吳國太開個綠燈。
 */
public class GivenGreenLight implements IStrategy {

    @Override
    public void operate() {
        System.out.println("求吳國太開個綠燈,放行!");
        
    }

}

妙計三:孫夫人斷后,擋住追兵:

package com.yangguangfu.strategy;
/**
 * 
 * @author trygf521@126.com:阿福
 * 孫夫人斷后,擋住追兵。
 */
public class BlackEnemy implements IStrategy {

    @Override
    public void operate() {
        System.out.println("孫夫人斷后,擋住追兵...");

    }

}
好了,大家看看,三個妙計是有了,那需要有個地方放妙計啊,放錦囊里:
package com.yangguangfu.strategy;
/**
 * 
 * @author trygf521@126.com:阿福
 *
 */
public class Context {
    
    private IStrategy strategy;
    //構造函數,要你使用哪個妙計
    public Context(IStrategy strategy){
        this.strategy = strategy;
    }
    
    public void operate(){
        this.strategy.operate();
    }

}
然后就是趙雲雄赳赳的揣着三個錦囊,拉着已步入老年行列,還想着娶純情少女的,色咪咪的劉備老爺子去入贅了,嗨,還別說,亮哥的三個妙計還真不錯,瞧瞧:
package com.yangguangfu.strategy;

public class ZhaoYun {

    /**
     * 趙雲出場了,他根據諸葛亮給他的交代,依次拆開妙計
     */
    public static void main(String[] args) {
        Context context;
        
        //剛到吳國的時候拆開第一個
        System.out.println("----------剛剛到吳國的時候拆開第一個---------------");
        context = new Context(new BackDoor());
        context.operate();//拆開執行
        System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n");
        
        //當劉備樂不思蜀時,拆開第二個
        System.out.println("----------劉備樂不思蜀,拆第二個了---------------");
        context = new Context(new GivenGreenLight());
        context.operate();//拆開執行
        System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n");
        
        //孫權的小追兵了,咋辦?拆開第三個錦囊
        System.out.println("----------孫權的小追兵了,咋辦?拆開第三個錦囊---------------");
        context = new Context(new BlackEnemy());
        context.operate();//拆開執行
        System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n");
    }

}
image
imageimage
 

11. 模板模式

定義一個操作中的算法骨架, 而將一些步驟延遲到子類中

個人感覺是定義一套流程”即算法骨架”, 置於骨架的內容, 要到實現時, 會有不同

比如: 我們使用沖泡咖啡和沖泡茶的例子

加工流程:

咖啡沖泡法:1.把水煮沸、2.用沸水沖泡咖啡、3.把咖啡倒進杯子、4.加糖和牛奶

茶沖泡法: 1.把水煮沸、2.用沸水沖泡茶葉、3.把 茶 倒進杯子、4.加蜂蜜

實踐步驟:

1>創建一個模板(抽象)類:Beverage(飲料) 這里包含”骨架”

package com.kaishengit.beverage;

public abstract class Beverage {
    /**
     * 沖泡咖啡或茶...流程
     */
    public final void create(){
        boilWater();//把水煮沸
        brew();//用沸水沖泡...
        pourInCup();//把...倒進杯子
        addCoundiments();//加...
    }


    public abstract void addCoundiments();

    public abstract void brew();
    
    public void boilWater() {
        System.out.println("煮開水");
    }
    
    public void pourInCup() {
        System.out.println("倒進杯子");
    }
}

2>創建一個咖啡類(Coffee)和茶(Tea)類,都繼承Beverage抽象類

1.咖啡(Coffee)

package com.kaishengit.beverage;

public class Coffee extends Beverage{

    @Override
    public void addCoundiments() {
        System.out.println("添加糖和牛奶");    }

    @Override
    public void brew() {
        System.out.println("用水沖咖啡");
    }
}

2. 茶(Tea)

package com.kaishengit.beverage;

public class Tea extends Beverage{

    @Override
    public void addCoundiments() {
        System.out.println("添加蜂蜜");
    }

    @Override
    public void brew() {
        System.out.println("用水沖茶");
    }

}

image

 

12. 觀察者模式

定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一主題對象

模式中的角色

  抽象主題(Subject):它把所有觀察者對象的引用保存到一個聚集里,每個主題都可以有任何數量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象。

  具體主題(ConcreteSubject):將有關狀態存入具體觀察者對象;在具體主題內部狀態改變時,給所有登記過的觀察者發出通知。

  抽象觀察者(Observer):為所有的具體觀察者定義一個接口,在得到主題通知時更新自己。

  具體觀察者(ConcreteObserver):實現抽象觀察者角色所要求的更新接口,以便使本身的狀態與主題狀態協調

image

想想自己blog的氣象站的例子(headfirst 設計模式中的例子)

 

13. 迭代器模式

迭代器模式提供一種方法順序訪問一個聚合對象中各個元素

image

迭代器角色(Iterator):迭代器角色負責定義訪問和遍歷元素的接口

具體迭代器角色(Concrete Iterator):具體迭代器角色要實現迭代器接口,並要記錄遍歷中的當前位置。

Aggregate (聚合): 聚合定義創建相應迭代器對象的接口

ConcreteAggregate (具體聚合): 具體聚合實現創建相應迭代器的接口,該操作返回ConcreteIterator的一個適當的實例

比如: 早期電視機, 按電視上按鈕換台那種, 當我們換頻道時, 重要的不是幾頻道, 而是節目內容.

在面向對象的軟件設計中, 我們經常會遇到一類集合對象, 這類集合對象的內部結構可能有着各種各樣的實現, 但是歸結起來, 無非有兩點是我們關心的: 一是集合內部的數據存儲結構, 二是遍歷這個集合內部的數據. Iterator 模式就是分離了集合對象的遍歷行為.

image

首先有一個抽象的聚集, 所謂聚集就是數據的集合, 可以循環去訪問它, 它只有一個方法 GetIterator()讓子類去實現, 用來獲得一個迭代器對象.

抽象迭代器: Iterator, 它用來訪問聚集的類, 封裝了一些方法, 通常會有 MoveNext(), CurrentItem(), First(), Next()

具體聚集 ConcreteList: 它實現了抽象聚集中的唯一方法, 同時再里面保存了一組數據

具體迭代器 ConcreteIterator: 具體迭代器, 它實現了迭代器中的4個方法, 在它的構造函數中需要接受一個具體聚集類型的參數.

 

14. 責任鏈模式

責任鏈模式使多個對象都有機會處理請求

image

抽象處理者 Handler: 定義出一個處理請求的接口,如果需要,接口可以定義出一個方法,以設定和返回對下家的引用。這個角色通常由一個抽象類或接口實現。

具體處理者(ConcreteHandler)角色:具體處理者接到請求后,可以選擇將請求處理掉,或者將請求傳給下家。由於具體處理者持有對下家的引用,因此,如果需要,具體處理者可以訪問下家。

比如: 請假,審批的例子, 在公司里,如果你的請假時間小於0.5天,那么只需要向項目經理打聲招呼就OK了, 如果超過了0.5天,但是還小於2天,那么就要去找人事部處理,當然,這就要扣工資了, 如果超過了2天,你就需要去找總經理了,工資當然也玩完了。那么,對於我們來說,這個流程就是這樣的。

 

image

也就是這樣一個過程,你需要和你的直接上級——項目經理去打交道,最終可能是項目經理給你回郵件,可能是人事部給你回郵件,也可能是總經理給你回郵件。內部的過程其實應該是個黑盒子,你並不知道內部的消息是如何處理的。你需要找到的,只是你想要第一個交付的對象而已.

下邊是一個審批例子的具體代碼.

抽象處理者角色

public abstract class Handler {
    /**
     * 持有下一個處理請求的對象
     */
    protected Handler successor = null;
    /**
     * 取值方法
     */
    public Handler getSuccessor() {
        return successor;
    }
    /**
     * 設置下一個處理請求的對象
     */
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }
    /**
     * 處理聚餐費用的申請
     * @param user    申請人
     * @param fee    申請的錢數
     * @return        成功或失敗的具體通知
     */
    public abstract String handleFeeRequest(String user , double fee);

具體處理者角色

項目經理

public class ProjectManager extends Handler {

    @Override
    public String handleFeeRequest(String user, double fee) {
        
        String str = "";
        //項目經理權限比較小,只能在500以內
        if(fee < 500)
        {
            //為了測試,簡單點,只同意張三的請求
            if("張三".equals(user))
            {
                str = "成功:項目經理同意【" + user + "】的聚餐費用,金額為" + fee + "元";    
            }else
            {
                //其他人一律不同意
                str = "失敗:項目經理不同意【" + user + "】的聚餐費用,金額為" + fee + "元";
            }
        }else
        {
            //超過500,繼續傳遞給級別更高的人處理
            if(getSuccessor() != null)
            {
                return getSuccessor().handleFeeRequest(user, fee);
            }
        }
        return str;
    }

}

部門經理

public class DeptManager extends Handler {

    @Override
    public String handleFeeRequest(String user, double fee) {
        
        String str = "";
        //部門經理的權限只能在1000以內
        if(fee < 1000)
        {
            //為了測試,簡單點,只同意張三的請求
            if("張三".equals(user))
            {
                str = "成功:部門經理同意【" + user + "】的聚餐費用,金額為" + fee + "元";    
            }else
            {
                //其他人一律不同意
                str = "失敗:部門經理不同意【" + user + "】的聚餐費用,金額為" + fee + "元";
            }
        }else
        {
            //超過1000,繼續傳遞給級別更高的人處理
            if(getSuccessor() != null)
            {
                return getSuccessor().handleFeeRequest(user, fee);
            }
        }
        return str;
    }

}

部長

public class GeneralManager extends Handler {

    @Override
    public String handleFeeRequest(String user, double fee) {
        
        String str = "";
        //總經理的權限很大,只要請求到了這里,他都可以處理
        if(fee >= 1000)
        {
            //為了測試,簡單點,只同意張三的請求
            if("張三".equals(user))
            {
                str = "成功:總經理同意【" + user + "】的聚餐費用,金額為" + fee + "元";    
            }else
            {
                //其他人一律不同意
                str = "失敗:總經理不同意【" + user + "】的聚餐費用,金額為" + fee + "元";
            }
        }else
        {
            //如果還有后繼的處理對象,繼續傳遞
            if(getSuccessor() != null)
            {
                return getSuccessor().handleFeeRequest(user, fee);
            }
        }
        return str;
    }

}

客戶端類 (測試)

public class Client {

    public static void main(String[] args) {
        //先要組裝責任鏈
        Handler h1 = new GeneralManager();
        Handler h2 = new DeptManager();
        Handler h3 = new ProjectManager();
        h3.setSuccessor(h2);
        h2.setSuccessor(h1);
        
        //開始測試
        String test1 = h3.handleFeeRequest("張三", 300);
        System.out.println("test1 = " + test1);
        String test2 = h3.handleFeeRequest("李四", 300);
        System.out.println("test2 = " + test2);
        System.out.println("---------------------------------------");
        
        String test3 = h3.handleFeeRequest("張三", 700);
        System.out.println("test3 = " + test3);
        String test4 = h3.handleFeeRequest("李四", 700);
        System.out.println("test4 = " + test4);
        System.out.println("---------------------------------------");
        
        String test5 = h3.handleFeeRequest("張三", 1500);
        System.out.println("test5 = " + test5);
        String test6 = h3.handleFeeRequest("李四", 1500);
        System.out.println("test6 = " + test6);
    }

}

輸出結果:

image

 

15. 命令模式

將一個請求封裝成為一個對象, 使可以用不同的請求對客戶進行參數化

image

命令角色(Command):聲明執行操作的接口。有java接口或者抽象類來實現。

具體命令角色(Concrete Command):將一個接收者對象綁定於一個動作;調用接收者相應的操作,以實現命令角色聲明的執行操作的接口

客戶角色(Client):創建一個具體命令對象(並可以設定它的接收者

請求者角色(Invoker):調用命令對象執行這個請求

接收者角色(Receiver):知道如何實施與執行一個請求相關的操作。任何類都可能作為一個接收者

比如: 電視機遙控器

電視機是請求的接收者Receiver,遙控器是請求的發送者Invoker, 遙控器上有一些按鈕,不同的按鈕對應電視機的不同操作Command. 抽象命令角色由一個命令接口來扮演, 有三個具體的命令類實現了抽象命令接口,這三個具體命令類分別代表三種操作:打開電視機、關閉電視機和切換頻道

代碼如下:
public interface Command {
    public void execute();
}


public class ConcreteCommand implements Command {

    private Receiver receiver = null;
    private String state;

    public ConcreteCommand(Receiver receiver){
       this.receiver = receiver;
    }  
    public void execute() {
       receiver.action();
    }
}


public class Receiver {
    public void action(){
       //真正執行命令操作的功能代碼
    }
}


public class Invoker {
    private Command command = null;

    public void setCommand(Command command) {
       this.command = command;
    }

    public void runCommand() {
       command.execute();
    }
}

public class Client {
    public void assemble(){
       //創建接收者
       Receiver receiver = new Receiver();
       //創建命令對象,設定它的接收者
       Command command = new ConcreteCommand(receiver);
       //創建Invoker,把命令對象設置進去
       Invoker invoker = new Invoker();
       invoker.setCommand(command);
    }
}
模擬電視機換台的代碼:
下面給個例子,是模擬對電視機的操作有開機、關機、換台命令。代碼如下

//命令接收者
public class Tv {
  public int currentChannel = 0;

  public void turnOn() {
     System.out.println("The televisino is on.");
  }

  public void turnOff() {
     System.out.println("The television is off.");
  }

  public void changeChannel(int channel) {
     this.currentChannel = channel;
     System.out.println("Now TV channel is " + channel);
  }
}

//執行命令的接口
public interface Command {
  void execute();
}

//開機命令
public class CommandOn implements Command {
  private Tv myTv;

  public CommandOn(Tv tv) {
     myTv = tv;
  }

  public void execute() {
     myTv.turnOn();
  }
}

//關機命令
public class CommandOff implements Command {
  private Tv myTv;

  public CommandOff(Tv tv) {
     myTv = tv;
  }

  public void execute() {
     myTv.turnOff();
  }
}

//頻道切換命令
public class CommandChange implements Command {
  private Tv myTv;

  private int channel;

  public CommandChange(Tv tv, int channel) {
     myTv = tv;
     this.channel = channel;
  }

  public void execute() {
     myTv.changeChannel(channel);
  }
}

//可以看作是遙控器吧
public class Control {
  private Command onCommand, offCommand, changeChannel;

  public Control(Command on, Command off, Command channel) {
     onCommand = on;
     offCommand = off;
     changeChannel = channel;
  }

  public void turnOn() {
     onCommand.execute();
  }

  public void turnOff() {
     offCommand.execute();
  }

  public void changeChannel() {
     changeChannel.execute();
  }
}

//測試類
public class Client {
  public static void main(String[] args) {
     // 命令接收者
     Tv myTv = new Tv();
     // 開機命令
     CommandOn on = new CommandOn(myTv);
     // 關機命令
     CommandOff off = new CommandOff(myTv);
     // 頻道切換命令
     CommandChange channel = new CommandChange(myTv, 2);
     // 命令控制對象
     Control control = new Control(on, off, channel);

     // 開機
     control.turnOn();
     // 切換頻道
     control.changeChannel();
     // 關機
     control.turnOff();
  }
}


執行結果為:
The televisino is on.
Now TV channel is 2
The television is off.

 

16. 狀態模式

狀態模式容許一個對象在其內部狀態改變時改變它的行為
image
上下文環境(Context):它定義了客戶程序需要的接口並維護一個具體狀態角色的實例,將與狀態相關的操作委托給當前的Concrete State對象來處理.
抽象狀態(State):定義一個接口以封裝使用上下文環境的的一個特定狀態相關的行為 
具體狀態(Concrete State):實現抽象狀態定義的接口
舉例:
電燈有兩個狀態,開(亮)與關(不亮),下面就用狀態模式來實現對電燈的控制
image
/// <summary>
    /// 電燈類,對應模式中的Context類
    /// </summary>
    public class Light
    {
        private LightState state;

        public Light(LightState state)
        {
            this.state = state;
        }

        /// <summary>
        /// 按下電燈開關
        /// </summary>
        public void PressSwich()
        {
            state.PressSwich(this);
        }

        public LightState State
        {
            get { return state; }
            set { state = value; }
        }    
    }

    /// <summary>
    /// 抽象的電燈狀態類,相當於State類
    /// </summary>
    public abstract class LightState
    {
        public abstract void PressSwich(Light light);
    }

    /// <summary>
    /// 具體狀態類, 開
    /// </summary>
    public class On : LightState
    {
        /// <summary>
        /// 在開狀態下,按下開關則切換到關的狀態。
        /// </summary>
        /// <param name="light"></param>
        public override void PressSwich(Light light)
        {
            Console.WriteLine("Turn off the light.");

            light.State = new Off();
        }
    }

    /// <summary>
    /// 具體狀態類,關
    /// </summary>
    public class Off: LightState
    {
        /// <summary>
        /// 在關狀態下,按下開關則打開電燈。
        /// </summary>
        /// <param name="light"></param>
        public override void PressSwich(Light light)
        {
            Console.WriteLine("Turn on the light.");

            light.State = new On();
        }
    }
客戶端代碼
class Program
    {
        static void Main(string[] args)
        {
            // 初始化電燈,原始狀態為關
            Light light = new Light(new Off());

            // 第一次按下開關,打開電燈
            light.PressSwich();
            // 第二次按下開關,關閉電燈
            light.PressSwich();

            Console.Read();
        }
    }
 
         
         
         
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM