設計模式-----代理模式

代理模式

定義

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

這裏寫圖片描述

代理模式也叫委託模式,許多模式,如狀態模式、策略模式、訪問者模式、本質上都是在特殊的場景下使用了代理模式。

  • Subject抽象主題角色
    抽象主體類可以是抽象類也可以是接口,是一個最普通的業務定義,沒有特殊的要求

  • RealSubject具體主題角色
    也叫委託角色、被代理角色,是業務邏輯的具體執行者

  • Proxy代理主題角色
    也叫做委託類、代理類。它負責對真實角色的應用,把所有抽象主題類定義的方法限制委託給真實主題角色實現,並且在真實主題角色處理完畢前後做預處理和善後處理工作。

public interface Subject {     
    //定義一個方法    
    public void request(); 
}
public class RealSubject implements Subject {     
    //實現方法     
    public void request() {             
        //業務邏輯處理,真正的業務邏輯處理類     
    } 
}
public class Proxy implements Subject {     
    //要代理哪個實現類     
    private Subject subject = null;         
    //默認被代理者     
    public Proxy(){             
        this.subject = new Proxy();     
    }     
    //通過構造函數傳遞代理者     
    public Proxy(Object...objects ){
        }     
     //實現接口中定義的方法     
    public void request() {             
        this.before();            
        this.subject.request();             
        this.after();     
    }     
    //預處理     
    private void before(){             
    //do something     
    }     
    //善後處理     
    private void after(){             
    //do something     
    } 
}

舉例

我們平常在玩遊戲打BOSS的時候,抽象爲程序:

這裏寫圖片描述

首先我們定義了一個接口,定義了遊戲中打BOSS的基本操作,比如登錄,殺死BOSS,升級。定義GamePlayer實現接口,完成具體操作。

public interface IGamePlayer {     
    //登錄遊戲     
    public void login(String user,String password);     
    //殺怪,網絡遊戲的主要特色     
    public void killBoss();     
    //升級    
    public void upgrade(); 
}
public class GamePlayer implements IGamePlayer {     
    private String name = "";     
    //通過構造函數傳遞名稱     
    public GamePlayer(String _name){             
        this.name = _name;     
    }     
    //打怪,最期望的就是殺老怪     
    public void killBoss() {             
        System.out.println(this.name + "在打怪!");     
    }     
    //進遊戲之前你肯定要登錄吧,這是一個必要條件     
    public void login(String user, String password) {             
        System.out.println("登錄名爲"+user+"的用戶"+this.name+"登錄成功!");     
     }     
//升級,升級有很多方法,花錢買是一種,做任務也是一種     
    public void upgrade() {             
        System.out.println(this.name + " 又升了一級!");     
    } 
}
public class Client {     
    public static void main(String[] args) {             
    //定義一個癡迷的玩家             
    IGamePlayer player = new GamePlayer("張三");            
    //開始打遊戲,記下時間戳             
    System.out.println("開始時間是:2009-8-25 10:45");             
    player.login("zhangSan", "password");             
    //開始殺怪             
    player.killBoss();             
    //升級             
    player.upgrade();             
    //記錄結束遊戲時間             
    System.out.println("結束時間是:2009-8-26 03:40");     
    } 
}

程序記錄了遊戲的開始時間以及殺死BOSS升級結束時間,但是我們發現升級太特喵的慢了,而且很無聊啊,於是我們請了代練:

這裏寫圖片描述

我們請了遊戲代練GamePlayerProxy 。

public class GamePlayerProxy implements IGamePlayer {     
    private IGamePlayer gamePlayer = null;          
    //通過構造函數傳遞要對誰進行代練     
    public GamePlayerProxy(IGamePlayer _gamePlayer){             
        this.gamePlayer = _gamePlayer;     
    }     
    //代練殺怪     
    public void killBoss() {             
        this.gamePlayer.killBoss();     
    }     
    //代練登錄     
    public void login(String user, String password) {             
        this.gamePlayer.login(user, password);     
    }     
    //代練升級     
    public void upgrade() {             
        this.gamePlayer.upgrade();     
    } 
}

但是代練是幫我們進行升級,同時它的遊戲操作需要遵循遊戲規範,因此我們仍然實現IGamePlayer 接口,並在實例化的同時將我們的遊戲實體傳入,有代練進行操作。

代理模式的優點

  • 職責清晰

    真實的角色就是實現實際的業務邏輯,不用關心其他非本職責的事務,通過後期的代理完成一件事務,附帶的結果就是編程簡潔清晰。
    
  • 高擴展性

    具體主題角色是隨時都會發生變化的,只要它實現了接口,甭管它如何變化,都逃不脫如來佛的手掌(接口),那我們的代理類完全就可以在不做任何修改的情況下使用。
    
  • 智能化

代理模式的使用場景

代理模式的使用是爲了減少自身的職責,本身只負責具體的業務實現,而一些瑣碎的事情則交給委託者進行實現,最經典的Spring AOP

代理模式的擴展

普通代理

普通代理要求客戶端只能訪問代理角色,而不能訪問真的角色。

這裏寫圖片描述

我們進行重構,在GamePlayer以及GamePlayerProxy增加構造函數。

public class GamePlayer implements IGamePlayer {        
    private String name = "";       
    //構造函數限制誰能創建對象,並同時傳遞姓名     
    public GamePlayer(IGamePlayer _gamePlayer,String _name) throws Exception{             
    if(_gamePlayer == null ){                    
        throw new Exception("不能創建真實角色!");               
    }else{                    
        this.name = _name;             
        }     
    }     
    //打怪,最期望的就是殺老怪     
    public void killBoss() {                
        System.out.println(this.name + "在打怪!");     
    }     
    //進遊戲之前你肯定要登錄吧,這是一個必要條件     
    public void login(String user, String password) {             
    System.out.println("登錄名爲"+user + "的用戶" + this.name + "登錄成功!");     
    }     
    //升級,升級有很多方法,花錢買是一種,做任務也是一種
    public void upgrade() {             
        System.out.println(this.name + " 又升了一級!");     
     } 
}

我們在構造函數中,傳遞一個IGamePlayer對象,檢查誰來創建對象,當然也可以進行類名的校驗,自行進行擴展。

至此我們代理,在進行創建的時候,只需要傳遞用戶名,然後在構造函數傳遞自身進行創建被代理對象即可。

強制代理

強制代理是通過被代理對象,找到代理對象。比如:我們去找某個明星做活動,我們想要繞過代理進行直接溝通,但是當我們找到了該演員,卻還是被告知需要找

這裏寫圖片描述

我們在接口中,增加getProxy()方法,並在GamePlayer實現中, 去實例化指定的代理類,然後在KillBoss等方法中,判斷是否有代理類,沒有則要求通過指定的代理類進行訪問。

public class GamePlayer implements IGamePlayer {     private String name = "";     
//我的代理是誰     
private IGamePlayer proxy = null;     
public GamePlayer(String _name){             
this.name = _name;      
}     
//找到自己的代理     
public IGamePlayer getProxy(){             
this.proxy = new GamePlayerProxy(this);             return this.proxy;     
}     
//打怪,最期望的就是殺老怪     
public void killBoss() {             
if(this.isProxy()){                     System.out.println(this.name + "在打怪!");             }else{                     
System.out.println("請使用指定的代理訪問");             
}     
} 

在上述中,如果我們直接新建玩家,則會要求我們訪問指定的代理。

public class GamePlayerProxy implements IGamePlayer {     private IGamePlayer gamePlayer = null;     
//構造函數傳遞用戶名     
public GamePlayerProxy(IGamePlayer _gamePlayer){             this.gamePlayer = _gamePlayer;     
}     
//代練殺怪     
public void killBoss() {             this.gamePlayer.killBoss();     
}     
//代練登錄     
public void login(String user, String password) {             this.gamePlayer.login(user, password);     
}     
//代練升級     
public void upgrade() {             this.gamePlayer.upgrade();     
}     
//代理的代理暫時還沒有,就是自己     
public IGamePlayer getProxy(){             
return this;     
} 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章