《设计模式之禅》学习笔记(十二)

第12章 代理模式

代理模式(Proxy Pattern)的定义如下:

Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供一种代理以控制对这个对象的访问。)

       

代理模式也叫做委托模式,它是一种基本设计技巧。

       

该模式下三种角色的定义:

  • Subject抽象主题角色

    抽象类或接口,是一个最普遍的业务类型定义

  • RealSubject具体主题角色

    被委托角色,是业务逻辑的具体执行者

  • Proxy代理主题角色

    委托类,负责对真实角色的应用,并负责预处理和善后工作。

       

通用源代码:

抽象主题类

public interface Subject {

// 定义一个方法

public void request();

}

真实主题类

public class RealSubject implements Subject {

// 实现方法

public void request() {

// 业务逻辑处理

}

}

代理类

public class Proxy implements Subject {

// 要代理哪个实现类

private Subject subject = null;

// 默认被代理者

public Proxy() {

this.subject = new RealSubject();

}

// 通过构造函数传递代理者

public Proxy(Subject subject) {

this.subject = subject;

}

// 实现接口中定义的方法

public void request() {

this.before();

this.subject.request();

this.after();

}

// 预处理

private void before() {

// do something

}

// 善后处理

private void after() {

// do something

}

}

     

代理模式的优点:

  • 职责清晰。真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的食物,通过后期的代理完成一件事物,附带的结果就是编程简洁清晰。
  • 高扩展性。代理类可以在不做任何修改的情况下适应具体主题角色的变化。
  • 智能化。动态代理可以实现智能化。

     

代理模式的扩展:

普通代理

在网络上代理服务器设置分为透明代理和普通代理,是什么意思呢?透明代理就是用户不用设置代理服务器地址,就可以直接访问,也就是说代理服务器对用户来说是透明的,不用知道它的存在;普通代理则是需要用户自己设置代理服务器的IP地址,用户必须知道代理的存在。设计模式中的普通代理就是我们要知道代理的存在,然后才能访问;强制代理则是调用者直接调用真实角色,而不用关心代理是否存在,其代理的产生是由真实角色决定的。

普通代理的要求就是客户端只能访问代理角色,而不能访问真实角色。在该模式下,调用者只知道代理而不用知道真实的角色是谁,屏蔽了真实角色的变更对高层模块的影响。该模式非常适合对扩展性要求较高的场合。

public class Client {

public static void main(String[] args) {

// 定义一个带练者

IGamePlayer proxy = new GamePlayerProxy("张三");

System.out.println("开始时间是:" + new Date());

proxy.login("zhangsan", "password");

proxy.killBoss();

proxy.upgrade();

System.out.println("结束时间是:" + new Date());

}

}

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 + "在打怪");

}

@Override

public void upgrade() {

System.out.println(this.name + "又升了一级");

}

}

public class GamePlayerProxy implements IGamePlayer {

private IGamePlayer gamePlayer = null;

public GamePlayerProxy(String name) {

try {

this.gamePlayer = new GamePlayer(this, name);

} catch (Exception ex) {

     

}

}

@Override

public void login(String user, String password) {

this.gamePlayer.login(user, password);

}

@Override

public void killBoss() {

this.gamePlayer.killBoss();

}

@Override

public void upgrade() {

this.gamePlayer.upgrade();

}

}

     

     

强制代理

一般的思维都是通过代理找到真实的角色,但是强制代理却是要"强制",你必须通过真实角色查找到代理角色,否则不能访问。

public class Client {

public static void main(String[] args) {

IGamePlayer player = new GamePlayer("张三");

IGamePlayer proxy = player.getProxy();

System.out.println("开始时间是:" + new Date());

proxy.login("zhangSan", "password");

proxy.killBoss();

proxy.upgrade();

System.out.println("结束时间是:" + new Date());

}

}

public class GamePlayer implements IGamePlayer {

private String name = "";

private IGamePlayer proxy = null;

public GamePlayer(String name) {

this.name = name;

}

@Override

public IGamePlayer getProxy() {

this.proxy = new GamePlayerProxy(this);

return this.proxy;

}

@Override

public void killBoss() {

if (this.isProxy()) {

System.out.println(this.name + "在打怪!");

} else {

System.out.println("请使用指定的代理访问");

}

}

@Override

public void login(String user, String password) {

if (this.isProxy()) {

System.out.println("登录名为" + user + "的用户" + this.name + "登录成功!");

} else {

System.out.println("请使用指定的代理访问");

}

}

@Override

public void upgrade() {

if (this.isProxy()) {

System.out.println(this.name + "又升了一级!");

} else {

System.out.println("请使用指定的代理访问");

}

}

private boolean isProxy() {

if (this.proxy == null) {

return false;

} else {

return true;

}

}

}

public class GamePlayerProxy implements IGamePlayer, IProxy {

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 void upgrade() {

this.gamePlayer.upgrade();

this.count();

}

@Override

public IGamePlayer getProxy() {

return this;

}

@Override

public void count() {

System.out.println("升级总费用是:150");

}

}

     

     

虚拟代理

虚拟代理就是在需要的时候才初始化主题对象,可以避免被代理对象较多引起的初始化缓慢的问题。其缺点是需要在每个方法中判断主题对象是否被创建。这就是虚拟代理,非常简单。

public class Proxy implements Subject {

private Subject subject = null;

@Override

public void request() {

if (subject == null) {

subject = new RealSubject();

}

subject.request();

}

}

     

动态代理

动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。

动态代理实现代理的职责,业务逻辑实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。对于日志、事务、权限等都可以在系统设计阶段不用考虑,而在设计后通过动态代理的方式加过去。

public class Client {

public static void main(String[] args) {

// 定义一个主题

Subject subject = new RealSubject();

// 定义一个Handler

InvocationHandler handler = new MyInvocationHandler(subject);

// 定义主题的代理

Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), handler);

// 定义的行为

proxy.doSomething("Finish!");

}

}

public class MyInvocationHandler implements InvocationHandler {

// 被代理的对象

private Object target = null;

// 通过构造函数传递一个对象

public MyInvocationHandler(Object obj) {

this.target = obj;

}

// 代理方法

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {

Object result = method.invoke(this.target, args);

return result;

}

}

public class DynamicProxy<T> {

public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {

// 寻找JoinPoint连接点,AOP框架使用元数据定义

if (true) {

// 执行一个前置通知

(new BeforeAdvice()).exec();

}

// 执行目标,并返回结果

return (T) Proxy.newProxyInstance(loader, interfaces, h);

}

}

// 抽象主题

public interface Subject {

// 业务操作

public void doSomething(String str);

}

// 真实主题

public class RealSubject implements Subject {

@Override

public void doSomething(String str) {

System.out.println("do something!--->" + str);

}

}

public interface IAdvice {

// 通知只有一个方法,执行即可

public void exec();

}

public class BeforeAdvice implements IAdvice {

@Override

public void exec() {

System.out.println("我是前置通知,我被执行了!");

}

}

posted @ 2012-12-27 16:15  qwertWZ  阅读(514)  评论(0编辑  收藏  举报