代理模式的定义:
对其他对象提供一种代理以控制对这个对象的访问。
形象比喻:
跟MM在网上聊天,一开头总是“hi,你好”,“你从哪儿来呀?”“你多大了?”“身高多少呀?”这些话,真烦人,写个程序做为我的Proxy吧,凡是接收到这些话都设置好了自动的回答,接收到其他的话时再通知我回答,怎么样,酷吧。
代理模式的主要作用:给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。
应用场景:
下面这个例子中含有日志动作,程序中经常需要为某些动作或者事件做下记录,一以便随时检查程序运行过程,排除错误信息。当需要在执行某些方法时留下日志信息,可能会这样写:
public class HelloSpeaker
{
private Logger logger = Logger.getLogger(this.getClass().getName());
public void hello(String name)
{
logger.log(Level.INFO,"hello method starts..."); //方法开始执行时留下日志
System.out.print("hello,"+name); //程序的主要功能
logger.log(Level.INFO,"hello method ends..."); //方法执行完毕时留下日志
}
}
对HelloSpeaker来说,日志的这种动作并不属于HelloSpeaker逻辑,这使得HelloSpeaker增加了额外的职责。
如果程序中这种日志到处都有需求,以上的写法势必造成程序员必须到处撰写这些日志动作的代码。这将使得维护日志代码的困难加大。有一些非类本身职责的相关动作也混到类中,如权限检查、事务管理,会使得类的负担加重,甚至混淆类本身的职责
另一方面,如果有一天不再需要日志的服务,那么将无法简单地将这些相关服务从现有的程序中移除。
上述问题可通过代理机制来解决,有两种代理方式:静态代理和动态代理。下面用静态代理来实现上述问题:
public interface IHello
{
public void hello(String name);
}
public class HelloSpeaker implements IHello
{
public void hello(String name)
{
System.out.print("hello,"+name);
}
}
public class HelloProxy implements IHello
{
private Logger logger = Logger.getLogger(this.getClass().getName());
private IHello helloObject;
public HelloProxy(IHello helloObject)
{
this.helloObject = helloObject;
}
public void hello(String name)
{
log("hello method starts..."); //日志服务
helloObject.hello(name); //执行业务逻辑
log("hello method ends..."); //日志服务
}
private void log(String ms)
{
logger.log(Level.INFO,MS);
}
}
在静态代理的实现中,代理类与被代理类必须实现同一个接口。在代理类中可以实现记录等相关服务,并在需要的时候再呼叫被代理类。这样被代理类就可以仅仅保留业务相关的职责了。