代理(Proxy)模式一

来源:互联网 发布:erp软件系统 报表 编辑:程序博客网 时间:2024/05/21 19:23

1.类图和角色

这里写图片描述
定义:Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供一种代理以控制对这个对象的访问)。
代理模式涉及的角色有:

  • 抽象主题角色:声明了真实主题和代理主题的共同接口,以便在任何可以使用真实主题的地方都可以使用代理角色。
  • 代理主题(Proxy)角色:代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象;与真实对象有共同的接口,以便可以在任何时候都可以代替真实对象;控制对真实对象的引用,负责在需要的时候操作真实的主题对象;通常,代理将调用传递给真实对象之前或之后,都要执行某些操作,而不是单纯的传递。
  • 真实主题(RealSubject)角色:定义了代理所代表的真实对象。

2.示例代码

抽象主题的代码:

public abstract class Subject {    public abstract void request();}

真实主题的代码:

public class RealSubject extends Subject {    public RealSubject() {}    public void request() {        System.out.println("Real subject");    }}

代理主题角色的代码:可以看出,代理主题处理将所有的请求委派给真实主题角色之外,还在委派之前和之后分别执行了一个preRequest()和postRequest()。

public class ProxySubject extends Subject {    private RealSubject realSubject;    public ProxySubject() {}    public void request() {        preRequest();        if (realSubject == null) {            realSubject = new RealSubject();        }        //调用真实对象的业务方法        realSubject.request();        postRequest();    }    private void preRequest() {        //在执行request()之前,要执行的代码    }    private void postRequest() {        //在执行request()之后,要执行的代码    }}

在使用代理主题的时候,要将变量声明类型声明为抽象主题的类型,而将真实的类型设为代理主题类型,代码如下:

    Subject subject = new ProxySubject();    subject.request();

从以上的代码可以看出代理是怎样工作的,首先,代理主题不改变主题接口;其次,地理主题起到的是一个传递请求的作用;最后代理主题在传递请求之前和之后可以执行特定的操作,而不是单纯的传递请求。

3.代理模式的应用

代理模式在现实中的使用非常多,非常典型的应用就是Spring AOP。还有就是java web应用中的Filter,它也是非常典型的代理的应用。

4.代理模式的扩展

4.1普通代理

普通代理的要求就是客户端只能访问代理角色,而不能访问真实角色。我们以游戏代练的场景为例,游戏代练者与实际的玩家有共同的接口,游戏代练者使用玩家的账号登录游戏,升级打怪,真实玩家支付一定的费用给游戏代练者。类图如下:
这里写图片描述
玩家接口代码如下:

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(IGamePlayer gamePlayer, String name) {        if (gamePlayer == null) {            throw new RuntimeException("不能创建真实角色");        } else {            this.name = name;        }    }    @Override    public void killBoss() {        //打怪    }    @Override    public void login(String user, String password) {        //登录    }    @Override    public void upgrade() {        //升级    }}

游戏代练者的代码:

public class GamePlayerProxy implements IGamePlayer {    private IGamePlayer gamePlayer = null;    public GamePlayerProxy(String name) {        gamePlayer = new GamePlayer(this, name);    }    @Override    public void killBoss() {        this.gamePlayer.killBoss();    }    @Override    public void login(String user, String password) {        this.gamePlayer.login(user, password);    }    @Override    public void upgrade() {        this.gamePlayer.upgrade();    }}

调用者代码:

    IGamePlayer proxy = new GamePlayerProxy("李四");    proxy.login("zhansan", "123");    proxy.killBoss();    proxy.upgrade();

调用者只知道代理而不用知道真实的角色是谁,屏蔽了真实角色的变更对高层模块的影响,真实角色想怎么改就怎么改,对高层没有任何的影响。在实际的项目中,一般都是通过约定来禁止new一个真实的角色。

4.2强制代理

强制代理是要强制必须通过真实角色查找到代理角色,否则不能访问。无论是通过代理类还是通过new生成一个真实角色,都不能访问,只能通过真实角色指定的代理类才可以访问。也就是说,客户端new一个真实角色对象,返回的却是代理角色。类图如下:
这里写图片描述
强制代理的接口代码

public interface IGamePlayer {    public void login(String name, String password);    public void killBoss();    public void upgrade();    public IGamePlayer2 getProxy();}

强制代理的真实角色代码:

public class GamePlayer implements IGamePlayer {    private String name = "";    private IGamePlayer  proxy = null;    public GamePlayer(String name_) {        this.name = name_;    }    @Override    public void login(String name, String password) {        if (isProxy()) {            System.out.println(this.name + "登录了!");        } else {            System.out.println("请使用代理访问");        }    }    @Override    public void killBoss() {        if (isProxy()) {            System.out.println(this.name + "打怪!");        } else {            System.out.println("请使用代理访问");        }    }    @Override    public void upgrade() {        if (isProxy()) {            System.out.println(this.name + "升级了!");        } else {            System.out.println("请使用代理访问");        }    }    @Override    public IGamePlayer getProxy() {        this.proxy = new GamePlayerProxy2(this);        return this.proxy;    }    private boolean isProxy() {        return (this.proxy == null ? false : true);    }}

增加了一个私有方法,用了检查是否是自己指定的代理对象。再来看看代理角色的代码:

public class GamePlayerProxy implements IGamePlayer {    private IGamePlayer gamePlayer = null;    public GamePlayerProxy(IGamePlayer gamePlayer) {        this.gamePlayer = gamePlayer;    }    @Override    public void login(String name, String password) {        this.gamePlayer.login(name, password);    }    @Override    public void killBoss() {        this.gamePlayer.killBoss();    }    @Override    public void upgrade() {        this.gamePlayer.upgrade();    }    @Override    public IGamePlayer2 getProxy() {        return this;    }}

客户端调用代码:

    //通过真实主题角色获取代理,再访问方法    IGamePlayer2 gamePlayer = new GamePlayer2("张三");    IGamePlayer2 proxy = gamePlayer.getProxy();    proxy.login("zhansan", "123");    proxy.upgrade();    proxy.killBoss();    //真实对象直接访问    IGamePlayer2 gamePlayer2 = new GamePlayer2("张三");    gamePlayer2.killBoss();    gamePlayer2.login("lili", "123");

运行代码可见,通过真实对象是不能直接访问方法的。由代码可以看出,强制代理的概念就是要从真实角色查找到代理角色,不允许直接访问真实角色。

0 0