JAVA设计模式之代理模式静态代理

1. 什么是代理模式?

官方定义是:为其他对象提供一种代理以控制对这个对象的访问。其实说白了让代理做你原来要做的事情。

2. 代理案例

举个例子,我们正常玩游戏,需要个人登录游戏账号,然后进行升级,这是一件漫长而又艰辛的事情,我们无法开外挂,因为要封号,于是我们找到代理厂家,沟通后代理商登录你的游戏账号进行升级,这就是代理

3. 静态代理

创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。
如图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200328210459396.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2w4OTQ3OTQz,size_16,color_FFFFFF,t_70
开始撸代码:

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 普通代理:

结构如图,对上述结构做小部分修改。
在这里插入图片描述

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. 动态代理

参考后面的文章传送门

发布了106 篇原创文章 · 获赞 87 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/l8947943/article/details/105168363