代理模式

来源:互联网 发布:编写高性能的JS 编辑:程序博客网 时间:2024/05/29 03:43

从游戏开始

从一个简单的例子开始讲吧。
在网游很火的那个时代,几乎人人都会玩玩游戏,时间久了就会发现大部分的网游都是一个套路,杀怪、升级、PK。我们简单地用程序表示下:
首先定义一个玩家接口IGamePlayer,提供三个简单的方法,表示游戏的过程。一个抽象类,定义玩家共有的属性。

/** * 玩家抽象类 * @author neil * */abstract class IGamePlayer{    /** 玩家姓名 */    protected String name;}/** * 玩家游戏行为接口 * @author neil * */interface IGamePlayerAction{    void login();    void killBoss();    void upgrade();}

玩家类继承IGamePlayer并实现接口IGamePlayerAction.

public class GamePlayer extends IGamePlayer implements IGamePlayerAction {    public GamePlayer(String name) {        this.name = name;    }    @Override    public void login() {        System.out.println("玩家"+name+"登录");    }    @Override    public void killBoss() {        System.out.println("玩家"+name+"打BOSS");    }    @Override    public void upgrade() {        System.out.println("玩家"+name+"升级");    }}

现在我们使用场景类来模拟下游戏过程:

public class Client {    public static void main(String[] args) {        GamePlayer gamePlayer = new GamePlayer("neil");        gamePlayer.login();        gamePlayer.killBoss();        gamePlayer.upgrade();    }}

得到的结果就是我们玩游戏的整个过程:

玩家neil登录玩家neil打BOSS玩家neil升级

日复一日的玩下去,玩家就要不停的经历这个过程,慢慢的有些人就开始不耐烦了。这时候游戏代练应运而生,玩家找到专门的游戏代练,付钱把自己的游戏账号交给代练,代练帮玩家把游戏等级升到满级。我们依旧用程序来简单模拟这个过程,定义一个代理类拥有玩家所有的行为方法,并拥有一个玩家对象:

package design_pattern.proxyPattern.easy;/** * 游戏代练 拥有玩家所有的行为 * @author neil * */public class GamePlayerProxy implements IGamePlayerAction {    private GamePlayer gamePlayer;    public GamePlayerProxy(GamePlayer gamePlayer) {        super();        this.gamePlayer = gamePlayer;    }    @Override    public void login() {        gamePlayer.login();    }    @Override    public void killBoss() {        gamePlayer.killBoss();    }    @Override    public void upgrade() {        gamePlayer.upgrade();    }}

代理没有自己的账号,需要持有一个玩家账号,游戏过程中使用该玩家账号,过程如下:

package design_pattern.proxyPattern.easy;public class Client {    public static void main(String[] args) {//      GamePlayer gamePlayer = new GamePlayer("neil");//      gamePlayer.login();//      gamePlayer.killBoss();//      gamePlayer.upgrade();        //首先要有一个玩家账号        GamePlayer gamePlayer = new GamePlayer("neil");        //把玩家账号交给游戏代练        GamePlayerProxy proxy = new GamePlayerProxy(gamePlayer);        //游戏代练进行繁琐无聊的游戏过程        proxy.login();        proxy.killBoss();        proxy.upgrade();    }}

游戏结果:

玩家neil登录玩家neil打BOSS玩家neil升级

最终还是玩家的账号在升级,但是玩家不用进行繁琐无聊的游戏过程,完全有代练代替玩家进行了。这就是代理模式。

代理模式

这里写图片描述

定义不好理解,我们不去管它。现在结合游戏代练的例子来看看代理模式的基本架构:
代理类(GamePlayerProxy):是必须的,它是整个代理模式的核心。
被代理的角色/实际对象(GamePlayer):代理类有了,接下来它要知道代理谁,就需要一个具体的角色了,这就是被代理对象,它来执行实际的业务逻辑代码。
抽象父角色(IGamePlayer):代理对象要知道实际对象什么时候该做什么事,就好像我们的例子,代练要知道它代表的玩家什么时候登录,什么时候打BOSS,什么时候升级,就需要代练和玩家有功能的行为,对程序来说就是要有共同的行为,通过实现同一个接口或者继承同一个父类实现。这个接口或者父类就是抽象父角色。

结合这三个角色我们就知道代理模式大概的意思了,当我们的实际对象要做某件事时,自己不用亲自去做,而是通过一个代理对象来帮忙做。

看到这里你可能会有些疑问,既然实际对象自己能够做到,即使是代理类最终也要执行被代理对象的方法,那么代理模式的意义在哪里呢?不要急,继续往下看。我们适当的修改下我们的代理中方法的实现:

/** * 游戏代练 拥有玩家所有的行为 * @author neil * */public class GamePlayerProxy implements IGamePlayerAction {     //...(重复代码省略)    @Override    public void login() {        System.out.println("登录之前存个档");        gamePlayer.login();    }    //...}

接下来我们再次执行场景类main方法,模拟代练游戏过程,得到结果:

登录之前存个档玩家neil登录玩家neil打BOSS玩家neil升级

我们发现,在被代理对象方法执行之前多了一个存档操作,但是我们没有去修改被代理对象的代码,仅仅修改了代理方法的实现。这就是代理的意义所在,在不修改被代理对象代码的情况下,在其方法执行前(当然也可是是之后)添加额外的操作。比如,如果某些被代理对象方法执行之前需要统一的日志打点功能,我们就可以使用代理进行这些额外的逻辑代码处理,而不用关心被代理对象的具体实现。当然,反过来思考下,当被代理对象的实现修改时,我们也不用再担心打点日志逻辑代码被影响到了。