1. 程式人生 > >代理模式、裝飾模式和介面卡模式

代理模式、裝飾模式和介面卡模式

代理模式

為其他物件提供一種代理以控制對這個物件的訪問。其實就是不直接使用原始物件構造出一個代理物件給客戶端使用。

動態代理,將代理者和被代理者直接解耦,一個代理者可以代理多個被代理物件。
靜態代理,只能代理實現同一個介面的被代理物件。
系統常見的例子如AIDL就是遠端代理。

步驟:

  1. 建立介面,定義一些方法
  2. 原始物件實現介面並重寫相關方法
  3. 建立代理物件實現介面並重寫相關方法,而且建構函式需要傳入一個原始物件,需要持有一個原始物件引用
  4. 客戶端建立一個原始物件和一個代理物件,然後通過代理物件去呼叫原始物件的方法
//1.建立介面
public interface ILawsuit
{
//提交申請 void submit(); // 進行舉證 void burden(); //開始辯護 void defend(); //訴訟完成 void finish(); } //2.建立原始物件 public class XiaoMin implements ILawsuit{ @Override public void submit() { //老闆拖欠小民的工資,小民申請仲裁 System.out.println("老闆年底拖欠工資,特此申請仲裁!"); } @Override
public void burden() { //小民提交證據 System.out.println("這是合同書和過去一年的銀行工資流水!"); } @Override public void defend() { //鐵證如山 System.out.println("證據確鑿,不需要再說什麼!"); } @Override public void finish() { //結果贏了 System.out.println("訴訟成功,判決老闆即日起七天內結算工資!"
); } } //3.建立代理物件 public class Lawyer implements ILawsuit{ private ILawsuit mLawsuit; //持有一個具體被代理者的引用 public Lawyer(ILawsuit lawsuit) { this.mLawsuit = lawsuit; //傳入原始物件 } @Override public void submit() { mLawsuit.submit(); } @Override public void burden() { mLawsuit.burden(); } @Override public void defend() { mLawsuit.defend(); } @Override public void finish() { mLawsuit.finish(); } } //4.客戶端呼叫 public class Client { public static void main(String[] args) { //構造出訴訟人小民 ILawsuit xiaomin = new XiaoMin(); //構造一個代理律師,並將小民傳遞進去 ILawsuit lawyer = new Lawyer(xiaomin); //律師提交申請 lawyer.submit(); //律師進行舉證 lawyer.burden(); //律師代小民辯護 lawyer.defend(); //完成訴訟 lawyer.finish(); } } //5.輸出結果 老闆年底拖欠工資,特此申請仲裁! 這是合同書和過去一年的銀行工資流水! 證據確鑿,不需要再說什麼! 訴訟成功,判決老闆即日起七天內結算工資!

裝飾模式

動態的給一個物件新增一些額外的職責。就增加功能來說,裝飾模式相比生成子類更為靈活。

裝飾模式是以對客戶端透明的方式擴充套件物件的功能,是繼承關係的一個替代方案。

其實就是建立幾個裝飾器,然後裝飾器裡面持有你要裝飾物件的引用,在呼叫被裝飾物件的方法前後增加我們想對它增加的方法,就是這樣。
系統中常見的例子就是 Context,ContextWrapper這些
步驟:
1. 建立抽象元件,一個抽象類是你具體要裝飾的物件的抽象類,裡面定義一些抽象方法
2. 建立具體元件,即一個具體的需要裝飾的類,繼承自上面的抽象元件,並實現抽象方法
3. 建立抽象裝飾者,一個抽象類繼承自抽象元件,並持有一個抽象元件的物件,實現抽象方法
4. 建立具體裝飾者,繼承自抽象裝飾者,實現抽象方法時加入需要裝飾的方法,起到裝飾的作用
5. 客戶端先建立具體元件,然後再建立具體裝飾者並傳入具體元件,最後呼叫具體方法實現裝飾效果

//1.建立抽象元件
public abstract class Person {
    /**
     * Person下有一個穿著的抽象方法 
     */
    public abstract void dressed();
}

//2.建立具體元件
public class Boy extends Person{
    @Override
    public void dressed() {
        System.out.println("穿了內衣內褲");
    }
}

//3.建立抽象裝飾者
public class PersonCloth extends Person{
    protected Person mPerson; //持有一個Person類的引用

    public PersonCloth(Person mPerson) {
        super();
        this.mPerson = mPerson;
    }

    @Override
    public void dressed() {
        mPerson.dressed();
    }
}

//4.建立具體裝飾者
public class ExpensiveCloth extends PersonCloth{

    public ExpensiveCloth(Person mPerson) {
        super(mPerson);
    }

    /**
     * 穿短袖 
     */
    private void dressShirt(){
        System.out.println("穿件短袖");
    }

    /**
     * 穿牛仔褲 
     */
    private void dressLeather(){
        System.out.println("穿牛皮衣");
    }

    /**
     * 穿鞋子 
     */
    private void dressJean(){
        System.out.println("穿牛仔褲");
    }

    @Override
    public void dressed() {  //重寫的方法
        super.dressed();
        dressShirt(); //起到了裝飾的作用
        dressLeather();
        dressJean();
    }
}

//5.客戶端
public class Client {
    public static void main(String[] args) {
        //首先有一個男孩
        Person person = new Boy();

        //
        PersonCloth personCloth = new ExpensiveCloth(person);
        personCloth.dressed();
        System.out.println("--------------");
    }
}

//6.輸出
穿了內衣內褲
穿件短袖
穿牛皮衣
穿牛仔褲
--------------

介面卡模式

介面卡模式把一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配無法在一起工作的兩個類可以在一起工作。

系統常見的例子就是listview和它的adapter
步驟:

  1. 定義客戶端所期待的介面和想呼叫的方法
  2. 定義目前已存在物件方法即需要被適配物件
  3. 定義一個介面卡物件,它將完成適配工作
//Target角色,客戶端所期待返回的物件
public interface FiveVolt {
    public int getVolt5();
}
//Adaptee角色,現有的物件需要被適配
public class Volt220 {
    public int getVolt220(){
        return 220;
    }
}
//Adapter角色,介面卡,將Adaptee轉換成客戶端需要的樣子
public class VoltAdapter extends Volt220 implements FiveVolt{ //繼承自被適配物件實現期待物件介面
    @Override
    public int getVolt5() {
        return 5;
    }
}
//客戶端呼叫
public class Test {
    public static void main(String[] args) {
        VoltAdapter adapter = new VoltAdapter();
        System.out.println("輸出電壓:" + adapter.getVolt5());
    }
}
//輸出
輸出電壓:5

三者的區別,代理模式不改變原始物件的功能,裝飾器模式會增強原始物件的功能,介面卡模式會改變原始物件對外暴露的介面

參考 《Android原始碼設計模式解析與實戰》 — 何紅輝 關愛民