天天看點

JAVA設計模式之代理模式靜态代理

1. 什麼是代理模式?

官方定義是:為其他對象提供一種代理以控制對這個對象的通路。其實說白了讓代理做你原來要做的事情。

2. 代理案例

舉個例子,我們正常玩遊戲,需要個人登入遊戲賬号,然後進行更新,這是一件漫長而又艱辛的事情,我們無法開外挂,因為要封号,于是我們找到代理廠家,溝通後代理商登入你的遊戲賬号進行更新,這就是代理

3. 靜态代理

建立一個接口,然後建立被代理的類實作該接口并且實作該接口中的抽象方法。之後再建立一個代理類,同時使其也實作這個接口。在代理類中持有一個被代理對象的引用,而後在代理類方法中調用該對象的方法。

如圖:

JAVA設計模式之代理模式靜态代理

開始撸代碼:

3.1 定義一個IGamePlayer接口

public interface IGamePlayer {
    // 登入遊戲
    void login(String user, String password);
    // 打怪
    void killBoss();
}      

3.2 定義一個玩家類

public class GamePlayer implements IGamePlayer {
    private String name = "";

    public GamePlayer(String _name) {
        this.name = _name;
    }

    @Override
    public void login(String user, String password) {
        System.out.println("登入名為" + user + "的使用者"+ this.name + "登入成功");
    }

    @Override
    public void killBoss() {
        System.out.println(this.name + "打boss");
    }
}      

3.3 定義一個代理類GamePlayerProxy

public class GamePlayerProxy implements IGamePlayer {
    private IGamePlayer gamePlayer = null;

    public GamePlayerProxy(IGamePlayer _gamePlayer) {
        this.gamePlayer = _gamePlayer;
    }

    @Override
    public void login(String user, String password) {
        this.gamePlayer.login(user, password);
    }

    @Override
    public void killBoss() {
        this.gamePlayer.killBoss();
    }
}      

3.4 代理上玩家的号進行代練,定義一個Client進行測試

public class Client {
    public static void main(String[] args) {
        // 定義一個玩家
        IGamePlayer player = new GamePlayer("張三");
        // 定義一個代練,代練玩家的号
        GamePlayerProxy proxy = new GamePlayerProxy(player);
        proxy.login("zhangsan", "123");
        proxy.killBoss();
    }
}      

4. 代理模式的擴充:普通代理和強制代理。

我們平時會聽到代理分為​

​透明代理​

​​和​

​普通代理​

​​,

​​

​透明代理​

​​:使用者不用設定代理伺服器位址直接通路,即代理伺服器對使用者來說是透明的,使用者不知道它的存在

​​

​普通代理​

​:普通代理和強制代理屬于一類,普通代理使用者必須知道代理的存在才能進行通路,即代理伺服器對使用者來說是不透明的。強制代理則調用者直接調用真實角色,不關心代理存在,代理的産生由真實角色決定。

4.1 普通代理:

結構如圖,對上述結構做小部分修改。

JAVA設計模式之代理模式靜态代理

4.1.1 接口不用變化,修改GamePlayer

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;
    }

    @Override
    public void login(String user, String password) {
        System.out.println("登入名為" + user + "的使用者"+ this.name + "登入成功");
    }

    @Override
    public void killBoss() {
        System.out.println(this.name + "打boss");
    }
}      

4.1.2 修改代理類

public class GamePlayerProxy implements IGamePlayer {
    private IGamePlayer gamePlayer = null;
    
    public GamePlayerProxy(String _name) {
        try {
            gamePlayer = new GamePlayer(this, _name);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void login(String user, String password) {
        this.gamePlayer.login(user, password);
    }

    @Override
    public void killBoss() {
        this.gamePlayer.killBoss();
    }
}      

4.1.3 修改測試類

public class Client {
    public static void main(String[] args) {
        // 建立一個代理對象
        IGamePlayer proxy = new GamePlayerProxy("張三");
        // 代理對象對賬号進行代理更新
        proxy.login("zhangsan", "123");
        proxy.killBoss();
    }
}      

運作結果完全相同,在該模式下,調用者隻知道代理而不用知道真實的角色是誰,真正的主角修改靈活,對高層子產品沒有什麼影響,該模式适合擴充性好的場合。

4.1 強制代理:

一般都是通過代理找到真實的角色,但是強制代理卻是通過真實的角色找到代理角色,否則不能通路。

​​

​舉個例子​

​:你有事情通過找到明星A去通路他的導演朋友,而不想直接找他的經紀人B去找,但是撥通A電話後A說太忙了,你去找他的經紀人

對上述圖結構進行修改

4.1.1 修改接口

public interface IGamePlayer {
    // 登入遊戲
    void login(String user, String password);
    // 打怪
    void killBoss();
    // 每個人都可以找到自己的代理
    IGamePlayer getProxy();
}      

4.1.2修改強制代理的真實角色GamePlayer

public class GamePlayer implements IGamePlayer {
    private String name = "";
    private IGamePlayer proxy = null;

    public GamePlayer(String _name) {
        this.name = _name;
    }

    @Override
    public void login(String user, String password) {
        if (this.isProxy()) {
            System.out.println("登入名為" + user + "的使用者" + this.name + "登入成功");
        }else {
            System.out.println("請使用指定代理通路");
        }
    }

    @Override
    public void killBoss() {
        if (this.isProxy()) {
            System.out.println(this.name + "打boss");
        }else {
            System.out.println("請使用指定代理通路");
        }
    }

    @Override
    public IGamePlayer getProxy() {
        this.proxy = new GamePlayerProxy(this);
        return this.proxy;
    }
    // 檢驗是否代理通路
    private boolean isProxy() {
        if (this.proxy == null) {
            return false;
        } else {
            return true;
        }
    }
}      

4.1.3 修改強制代理的代理類

public class GamePlayerProxy implements IGamePlayer {
    private IGamePlayer gamePlayer = null;

    public GamePlayerProxy(IGamePlayer _gamePlayer) {
       this.gamePlayer = _gamePlayer;
    }

    @Override
    public void login(String user, String password) {
        this.gamePlayer.login(user, password);
    }

    @Override
    public void killBoss() {
        this.gamePlayer.killBoss();
    }

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

4.1.4 修改測試類Client

public class Client {
    public static void main(String[] args) {
        // 1直接通路真實角色
        IGamePlayer player = new GamePlayer("張三");
        player.login("zhangsan", "123"); // 輸出:請使用指定代理通路
        player.killBoss();// 輸出:請使用指定代理通路
        // 2.直接通路代理類
        IGamePlayer player1 = new GamePlayer("張三");
        IGamePlayer proxy1 = new GamePlayerProxy(player1);
        proxy1.login("zhangsan", "123");// 輸出:請使用指定代理通路
        proxy1.killBoss();// 輸出:請使用指定代理通路
        // 3.使用強制代理通路,即找到明确的代理
        IGamePlayer player2 = new GamePlayer("張三");
        IGamePlayer proxy2 = player2.getProxy();
        proxy2.login("zhangsan", "123"); // 輸出:登入名為zhangsan的使用者張三登入成功
        proxy2.killBoss(); // 輸出:張三打boss
    }
}      

5. 動态代理