代理模式

1、代理模式的动机

2、代理模式的定义

代理模式(Proxy Pattern) :给某一个对象提供一个代理,并由代理对象控制对原对象的引用,它是一种对象结构型模式;

3、代理模式的类结构图

image
分析如下:

4、优缺点和适用场景

优点:

缺点:

适用场景:

5、实例

5.1 普通代理

特点: 客户端必须知道代理存在,且只能通过代理对象访问真实对象,不能够直接访问真实对象;

类图:
image

抽象主题

public interface IGamePlayer {
//  登录
    void login(String user, String password);
//  打怪
    void killBoss();
//  升级
    void upgrade();
}

具体主题

public class GamePlayer implements IGamePlayer {
    private String name;

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

    public void login(String user, String password) {
        System.out.println("登录名为"+user+"的用户"+this.name + "登录成功");
    }

    public void killBoss() {
        System.out.println(this.name + "在打怪");
    }

    public void upgrade() {
        System.out.println(this.name + "在升级");
    }
}

主题代理

public class GamePlayerProxy implements IGamePlayer {
    private IGamePlayer gamePlayer;

    public GamePlayerProxy(String gamePlayer) {
        this.gamePlayer = new GamePlayer(gamePlayer);
    }

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

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

    public void upgrade() {
        this.gamePlayer.upgrade();
    }
}

客户端

public class GeneralProxyClient {
    public static void main(String[] args) {
        IGamePlayer proxy = new GamePlayerProxy("郑印");
        proxy.login("XXXX", "134138");
        proxy.killBoss();
        proxy.upgrade();
    }
}

5.2 强制代理

特点: 必须通过真实对象找到代理对象才能访问真实对象,否则无论是创建一个代理或者一个真实对象都不能访问真实对象。代理对象是通过真实对象来管理的;
类图
image
抽象主题

public interface IGamePlayerV2 extends IGamePlayer {
    IGamePlayerV2 getProxy();
}

真实主题

public class GamePlayerV2 implements IGamePlayerV2 {
    private IGamePlayerV2 gamePlayerV2;
    private String name;

    public GamePlayerV2(String name) {
        this.name = name;
    }

    public void login(String user, String password) {
        if (gamePlayerV2 != null) {
            System.out.println("登录名为" + user + "的用户" + this.name + "登录成功");
        } else {
            System.out.println("请用指定代理访问");
        }

    }

    public void killBoss() {
        if (gamePlayerV2 != null) {
            System.out.println(this.name + "在打怪");
        } else {
            System.out.println("请用指定代理访问");
        }

    }

    public void upgrade() {
        if (gamePlayerV2 != null) {
            System.out.println(this.name + "在升级");
        } else {
            System.out.println("请用指定代理访问");
        }
    }

    public IGamePlayerV2 getProxy() {
        this.gamePlayerV2 = new GamePlayerV2Proxy(this);
        return this.gamePlayerV2;
    }
}

代理主题

public class GamePlayerV2Proxy implements IGamePlayerV2 {

    private IGamePlayerV2 realPlayer;

    public GamePlayerV2Proxy(IGamePlayerV2 realPlayer) {
        this.realPlayer = realPlayer;
    }

    public void login(String user, String password) {
        realPlayer.login(user,password);
    }

    public void killBoss() {
        realPlayer.killBoss();
    }

    public void upgrade() {
        realPlayer.upgrade();
    }

    public IGamePlayerV2 getProxy() {
        return this;
    }
}

客户端测试

public class ForceProxyClient {
    public static void main(String[] args) {
        IGamePlayerV2 gamePlayerV2 = new GamePlayerV2("郑印");
        IGamePlayerV2 proxy = gamePlayerV2.getProxy();
        proxy.login("XXXX", "1234");
        proxy.killBoss();
        proxy.upgrade();
    }
}

5.3 动态代理

特点: 在实现阶段不用关心代理谁,只在运行阶段才指定代理谁。相对来说,自己写代理类就是静态代理;
类图
image
代理处理类

public class DynamicProxyHandle implements InvocationHandler {
    private Object object;

    public DynamicProxyHandle(Object object) {
        this.object = object;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(object, args);
        return result;
    }
}

invoke方法完成对真实对象方法的调用;

客户端

public class DynamicProxyClient {
    public static void main(String[] args) {
        GamePlayer iGamePlayer = new GamePlayer("郑印");
        DynamicProxyHandle dynamicProxyHandle = new DynamicProxyHandle(iGamePlayer);
        IGamePlayer proxy = (IGamePlayer) Proxy
                .newProxyInstance(iGamePlayer.getClass().getClassLoader(), iGamePlayer.getClass().getInterfaces(), dynamicProxyHandle);
        proxy.login("XXXX", "134138");
        proxy.killBoss();
        proxy.upgrade();
    }
}