代理模式
定义:
代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问,用一个对象代替本尊对象。
思想:
代理模式主要用于控制访问权限。
动机:
有时候一个对象会很大,而大部分情况用户调用此对象不需要对此对象进行完整的实例化,可能仅仅需要一小部分功能。用代理可以减少系统资源的浪费,快速地给用户相应,而不必加载无用的东西。
有时候对象的一部分属性或行为不能给某些用户访问,某些用户访问后可能会对整个对象的公平性,真实性有影响。这时候就要针对不同的调用者控制不同的方法访问权限,以达到对象的公平性
实用性:
1) 远程代理(Remote Proxy)为一个位于不同的地址空间的对象提供一个本地的代理对象。这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)
2) 虚拟代理(Virtual Proxy)根据需要创建开销很大的对象。如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
3) 保护代理(Protection Proxy)控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
4) 智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。
5) Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。
类图:
实例:
Subject接口:
package com.mylearn.designmodel.proxy; /** * Created by IntelliJ IDEA. * User: yingkuohao * Date: 13-9-30 * Time: 上午10:49 * CopyRight:360buy * Descrption: 主题对象: * 注意:1.名称和兴趣一般都是自己定义的,如果其他人修改的话会使自己的投票率降低,所以应该限制其他人修改自己的属性; * 2. 自己不能给自己投票,否则票数就不准了。所以应限制自己给自己修改投票 * To change this template use File | Settings | File Templates. */ public interface Subject { /** * 投票 * * @param rating */ public void setHotOrNotRaing(int rating); /** * 获取投票数量 * * @return */ public int getHotOrNotRating(); public String getName(); public void setName(String name); public int getRating(); public void setRating(int rating); public String getIntrestes(); public void setIntrestes(String intrestes); public int getRatingCount(); public void setRatingCount(int ratingCount); } |
SubjectImpl:
package com.mylearn.designmodel.proxy; /** * Created by IntelliJ IDEA. * User: yingkuohao * Date: 13-9-30 * Time: 上午10:49 * CopyRight:360buy * Descrption: 主题对象: * 注意:1.名称和兴趣一般都是自己定义的,如果其他人修改的话会使自己的投票率降低,所以应该限制其他人修改自己的属性; * 2. 自己不能给自己投票,否则票数就不准了。所以应限制自己给自己修改投票 * To change this template use File | Settings | File Templates. */ public class SubjectImpl implements Subject { private String name; //名称 private String intrestes; //兴趣 private int rating; private int ratingCount; /** * 投票 * @param rating */ public void setHotOrNotRaing(int rating) { this.rating += rating; ratingCount++; } /** * 获取投票数量 * @return */ public int getHotOrNotRating() { if (ratingCount == 0) return 0; return (rating / ratingCount); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getRating() { return rating; } public void setRating(int rating) { this.rating = rating; } public String getIntrestes() { return intrestes; } public void setIntrestes(String intrestes) { this.intrestes = intrestes; } public int getRatingCount() { return ratingCount; } public void setRatingCount(int ratingCount) { this.ratingCount = ratingCount; } } |
SubjectProxy :
package com.mylearn.designmodel.proxy; import java.lang.reflect.Proxy; /** * Created by IntelliJ IDEA. * User: yingkuohao * Date: 13-9-30 * Time: 下午4:18 * CopyRight:360buy * Descrption: 动态代理, 主题的代理类 * To change this template use File | Settings | File Templates. */ public class SubjectProxy { public static Subject getOwnerProxy(Subject subject) { return (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), new OwnerInvocationHandler(subject)); } public static Subject getNotOwnerProxy(Subject subject) { return (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), new NotOwnerInvocationHandler(subject)); } } |
NotOwnerInvocationHandler :NotOwner的代理类
package com.mylearn.designmodel.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * Created by IntelliJ IDEA. * User: yingkuohao * Date: 13-9-30 * Time: 上午11:17 * CopyRight:360buy * Descrption: * 非所有者代理类,他只能处理投票方法和get方法,不能修改owner的属性 * To change this template use File | Settings | File Templates. */ public class NotOwnerInvocationHandler implements InvocationHandler { private Subject subject; public NotOwnerInvocationHandler(Subject subject) { this.subject = subject; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().startsWith("get") || method.getName().equals("setHotOrNotRaing")) { return method.invoke(subject, args); } else if (method.getName().startsWith("set")) { //如果其他人想修改当事人的属性,直接抛出异常 throw new IllegalAccessException(); } return null; } } |
OwnerInvocationHandler :owner的代理类
package com.mylearn.designmodel.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * Created by IntelliJ IDEA. * User: yingkuohao * Date: 13-9-30 * Time: 上午11:17 * CopyRight:360buy * Descrption: java的动态代理机制 :主要控制对象的行为,装饰模式主要是扩展对象的行为 * 所有者代理类:他能修改自己的属性,查看get方法,但是不能进行投票 * To change this template use File | Settings | File Templates. */ public class OwnerInvocationHandler implements InvocationHandler { private Subject subject; public OwnerInvocationHandler(Subject subject) { this.subject = subject; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("setHotOrNotRaing")) { //如果自己想修改自己的评分,直接抛出异常 throw new IllegalAccessException(); } else if (method.getName().startsWith("get") || method.getName().startsWith("set")) { return method.invoke(subject, args); } return null; } } |
客户端:
package com.mylearn.designmodel.proxy; /** * Created by IntelliJ IDEA. * User: yingkuohao * Date: 13-9-30 * Time: 下午4:20 * CopyRight:360buy * Descrption: 客户端,测试类 * To change this template use File | Settings | File Templates. */ public class Client { public static void main(String args[]) { Subject subject = new SubjectImpl(); Subject subjectOwner = SubjectProxy.getOwnerProxy(subject); subjectOwner.setName("zhangsan"); subjectOwner.setIntrestes("game"); int rate = subjectOwner.getHotOrNotRating(); System.out.println("rate = " + rate); try { subjectOwner.setHotOrNotRaing(10); } catch (Exception e) { System.out.println("can't set rating from owner proxy!"); } Subject subjectNotOnwer = SubjectProxy.getNotOwnerProxy(subject); try { subjectNotOnwer.setName("lisi"); } catch (Exception e) { System.out.println("can't set name from notowner proxy!"); } subjectNotOnwer.setHotOrNotRaing(10); System.out.println("rate = " + subjectNotOnwer.getHotOrNotRating()); } } |
其他:
RMI那一篇文章其实也是代理模式,可以参考。