天天看點

不學無數——Java代理模式

1. 代理

Provide a surrogate or placeholder for another object to control access to it(為其他對象提供一種代理以控制對這個對象的通路)

1.1 什麼是代理

代理是基本的設計模式之一,它是你為了提供額外或者不同的行為,而插入的用來代替”實際對象“的對象。這些操作通常是涉及到與”實際對象“的通信。

舉個現實中和的例子:假設你有一套房子要出租,一種方法是你直接去網上釋出出租資訊,然後直接帶要租房子的人來看房子,但是可能你很忙,你沒有時間去處理這些事情,是以你可以去找中介,讓中介幫你處理這些瑣碎事情,中介實際上就是你的代理。本來是你要做的事情,現在中介幫助你一一處理。當我們需要租房子時,隻能找房屋中介,而不能找房東了,因為房東已經和房屋中介簽訂了協定。是以房屋中介代理的存在就是為了攔截我們對于房東的直接通路。

下面在代碼中展現出上面的例子

現在有一個

House

,有價格和顔色兩個屬性。

class Home{
    Integer price;
    String color;
    -----get.set方法
}

           

有個房主的接口,每個房主都具有出租的功能。

interface Homeowner{
    public void LeaseHouse(Home home);
}

           

現在有一個真實的房主實作了這個接口

class RealHomeowner implements Homeowner{
    @Override
    public void LeaseHouse(Home home) {
        System.out.println("房價是 "+ home.price);
        System.out.println("房子顔色是 "+ home.color);
    }
}

           

現在有一個房屋代理,房屋代理也具備出租的功能,但是他出租的是和他簽訂協定房主的房子。在和房主簽訂協定之後他會對房子進行處理,并且将價格提高。

class HomeProxy implements Homeowner{

    private Homeowner homeowner;

    public HomeProxy(Homeowner homeowner){
        this.homeowner = homeowner;
    }
    @Override
    public void LeaseHouse(Home home) {
        System.out.println("裝修房子");
        home.color="red";
        System.out.println("提升價格");
        home.price=home.price+1000;
        homeowner.LeaseHouse(home);
    }
}

           

當房屋代理将房子整理好了以後,就将房源資訊放入到網上供人們選擇

public static void consume(Homeowner homeowner,Home home){
    if (homeowner instanceof HomeProxy){
        homeowner.LeaseHouse(home);
    }
    else {
        System.out.println("請找房屋代理");
    }
}

           

在主方法中調用

consume()

方法

public class ProxyDemo {
    public static void main(String[] args) {
        consume(new HomeProxy(new RealHomeowner()),new Home(1000,"black"));
        System.out.println("--------------------------------");
        consume(new RealHomeowner(),new Home(1000,"black"));
    }
}

           

發現直接和房東直租已經被拒絕了,隻能通過代理進行租房。列印資訊如下:

裝修房子
提升價格
房價是 2000
房子顔色是 red
--------------------------------
請找房屋代理

           

從上面可以看出代理其實分為三個角色:

  1. 抽象的主題角色:隻是業務類型的定義。
  2. 具體的主題角色:也叫做被代理角色,是業務邏輯的真正執行者。
  3. 代理主題角色: 也叫做委托類、代理類。它負責對真實角色的應用,把所有抽象主題類定義的方法限制委托給真實主題角色實作,并且在真實主題角色處理完畢前後做預處理和善後處理工作。

1.2 什麼時候使用代理

在任何時候,隻要你想要從額外的操作從“實際的對象”分離到不同的地方,特别是當你希望能夠很容易的做出修改,從沒有使用額外操作轉為使用這些操作,或者反過來時,代理就顯得很有用。

還是剛才的現實的例子,我們為什麼要把房子給房屋代理?

  • 例如你在美國有一套房,而你在北京居住和上班,這時候你沒時間去和租房的人打交道。是以将房子交給房屋代理。
為其他對象提供一種代理以控制對這個對象的通路。在某些情況下,一個客戶不想或者不能直接引用另一個對象,而代理對象可以在用戶端和目标對象之間起到中介的作用

對應到代碼中的意思就是:如果你在北京要處理美國的房子,每次有人想租房子,或者你租的房子出現了問題,你都得坐飛機回去和房客進行交涉或者維修。代碼中最常見的就是

Web Service

的工作原理,即你隻是想和另一台機器進行通信,你不想管中間的通信原理,例如網絡打包、通信、解包等一系列複雜的問題,是以我們使用代理将這一系列通信的問題進行了包裝,再由代理進行通信的功能。

  • 對于房屋的維修或者和房租打交道嫌麻煩,隻想把房子租出去收錢就行,是以直接交給房屋代理進行打理。

對應到代碼中的意思就是:一個類的單一職能原則,對于房東來說,隻會租房的功能,但是如果不裝修,不打理的話是很難租出去的,是以交給了房屋代理,房屋代理進行裝修,後期整理在進行出租。代碼中常見的實作就是對于權限的過濾,一個類有一個功能,而這個功能隻适合一部分的使用者使用,是以利用代理進行權限的過濾。

代理展現了一個類的單一職能原則,就是一個類隻做自己的功能,不摻雜其他東西,這樣這個類被修改的幾率才會最小。

1.3 代理的優點

  • 職責清晰:真實的角色就是現實實際的業務邏輯,不用關系其他非本職的東西,通過後期的代理完成一件事務,附帶的結果就是變成簡潔清晰
  • 高擴充性:具體主題角色是随時發生變化的,隻要它實作了接口,是以它無論怎麼變化,都逃不脫如來佛的手掌(接口)的控制,那我們的代理類完全可以在不做任何修改的情況下使用。
  • 智能化:在動态代理中可以展現出具體的智能化,關于動态代理在下一節中進行講解。

1.4 強制代理

強制代理是代理模式的一種延伸,代理模式是通過代理找到實際的角色動作,但是強制代理要求通過實際角色獲得代理,不然不讓通路。在現實中展現就是,房主和房屋代理簽訂了合同,如果有房客想要租這個房就隻能找這個固定的房屋代理,不能找其他的。不管是new出來一個房屋代理也好,還是直接找房主也好,都是租不了房的。

強制代理接口如下,隻是增加了一個

getProxy()

方法,獲得指定的代理:

interface Homeowner{
    public void LeaseHouse(Home home);
    public Homeowner getProxy();
}

           

實作類也作了一些的修改,先看房主角色

class RealHomeowner implements Homeowner{
    private Homeowner proxy;
    @Override
    public void LeaseHouse(Home home) {
        if (isProxy()){
            System.out.println("房價是 "+ home.price);
            System.out.println("房子顔色是 "+ home.color);
        }else {
            System.out.println("請找房屋代理");
        }
    }
    // 獲得自己的代理
    @Override
    public Homeowner getProxy() {
        this.proxy=new HomeProxy(this);
        return this.proxy;
    }
    // 校驗是否是代理通路
    private Boolean isProxy(){
        if (this.proxy == null){
            return false;
        }else {
            return true;
        }
    }
}

           

強制代理的代理類

class HomeProxy implements Homeowner{

    private Homeowner homeowner;

    public HomeProxy(Homeowner homeowner){
        this.homeowner = homeowner;
    }
    @Override
    public void LeaseHouse(Home home) {
        System.out.println("裝修房子");
        home.color="red";
        System.out.println("提升價格");
        home.price=home.price+1000;
        homeowner.LeaseHouse(home);
    }
    // 因為代理上面沒有代理就傳回自己
    @Override
    public Homeowner getProxy() {
        return this;
    }
}

           

如果此時代理又被代理了,可以繼續延伸下去。

此時如果按照正常的代理模式進行通路的話,

public static void main(String[] args) {
        RealHomeowner realHomeowner=new RealHomeowner();
        Home home=new Home(1000,"red");
        realHomeowner.LeaseHouse(home);
        HomeProxy homeProxy = new HomeProxy(realHomeowner);
        homeProxy.LeaseHouse(home);
}

           

發現在進行出租房子的時候,進行了拒絕出租。這個代理對象是你new出來的,是以真是對象當然不認,這就好比你和A代理公司簽訂了合同,但是房客去B代理公司租你的房子,肯定是不行的。

裝修房子
提升價格
請找房屋代理
           

此時如果更改成如下:

public static void main(String[] args) {
    RealHomeowner realHomeowner=new RealHomeowner();
    Home home=new Home(1000,"red");
    Homeowner homeProxy = realHomeowner.getProxy();
    homeProxy.LeaseHouse(home);
}

           

就會發現房子被租出去了

裝修房子
提升價格
房價是 2000
房子顔色是 red

           
強制代理的概念就是要從真是對象查找代理角色,不允許直接通路真實角色

1.5 代理實作多個接口

一個類可以實作多個接口,完成不同的任務的整合,也就說代理類不僅可以實作主題接口,也可以實作其他接口完成不同的任務,而且代理的目的就是在目标對象方法的基礎上作增強,這種增加本質上就是對目标對象的方法進行攔截過濾。比如現在房屋中介不想自己進行裝修房子了,于是把裝修單獨拆出來作為一個接口,在内部進行實作。

interface RenovationInterface{
    public void Renovation(Home home,String color);
}

           

代理類

class HomeProxy implements Homeowner , RenovationInterface{
    private Homeowner homeowner;
    public HomeProxy (Homeowner homeowner){
        this.homeowner = homeowner;
    }
    @Override
    public void LeaseHouse(Home home) {
        System.out.println("裝修房子");
        this.Renovation(home,"red");
        System.out.println("提升價格");
        home.price=home.price+1000;
        homeowner.LeaseHouse(home);
    }

    @Override
    public Homeowner getProxy() {
        return this;
    }

    @Override
    public void Renovation(Home home, String color) {
        home.color = color;
    }
}

           

一個代理類可以代理多個真實的角色,并且真實角色之間可以有耦合關系,可以自行的進行擴充。