读书笔记:headfirst 设计模式 ,大话设计模式
代理模式概念
代理模式:为其他对象提供一种代理以控制对这个对象的访问
代理模式式结构图
结构代码
public interface Subject {
void request();
}
public class RealSubject implements Subject{
@Override
public void request() {
System.out.println("真实的请求");
}
}
public class Proxy implements Subject {
private RealSubject realSubject;
@Override
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
realSubject.request();
}
}
public class TestClient {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.request();
}
}
代理模式与装饰者模式与适配器模式,外观(门面)模式的区别
代理结构上类似装饰者模式
但是目的不一样,装饰者是为对象增加行为,代理是控制对象的访问
代理和适配器都是挡在其他对象前面,并负责转发给它们,适配器会改变对象适配的接口,而代理则实现相同的接口
模式 | 描述 |
---|---|
代理 | 包装一个对象,并控制它的访问 |
装饰者 | 包装一个对象,并提供额外的行为 |
适配器 | 包装一个对象,并提供不同的接口 |
外观(门面) | 包装许多对象以简化它们的接口 |
如何让客户使用代理而不是真正的对象?提供一个工厂,实例化并返回主题
代理模式的应用
- 远程代理,为一个对象在不同地址空间提供局部代表
- 虚拟代理,根据需要创建开销大的对象
- 安全(保护)代理,用来控制真实对象访问时的权限
- 智能指引,当调用真实对象时,代理处理另外一些事
远程代理
远程代理:好比远程对象的本地代表
远程对象:不同地址空间(不同java虚拟机)运行的远程对象
本地代表:是一种可以由本地方法调用的对象,其行为会转发到远程对象中
RMI :远程方法调用
虚拟代理
虚拟代理:
作为创建开销大的对象的代表,虚拟代理经常知道我们真正需要一个对象的时候才去创建它,
当对象创建前后创建中时,由虚拟代理来扮演对象的替身
对象创建后,代理就会请求直接委托给对象
保护代理
使用javaAPI的动态代理来实现保护代理案例
动态代理
javaAPI中,在运行时动态的创建代理类,实现一个或多个接口,并将方法的调用转发到你所指定的类
案例需求
用户信息,用户自己可以设置修改自己的姓名,兴趣,但是不能给自己点赞,
其他用户可以给别人点赞,但是不能修改别人的姓名和兴趣,
利用动态代理创建保护代理OwnerProxy和NonOwnerProxy
代码实现
// 用户信息接口
public interface Person {
String getName();
String getInterests();
int getRating();
void setName(String name);
void setInterests(String interests);
void setRating();
}
// 用户信息实现
public class PersonImpl implements Person {
private String name;
private String interests;
private int rating;
@Override
public String getName() {
return name;
}
@Override
public String getInterests() {
return interests;
}
@Override
public int getRating() {
return rating;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public void setInterests(String interests) {
this.interests = interests;
}
@Override
public void setRating() {
rating++;
}
}
测试结果:
Tom 登陆
Tom 设置自己写兴趣为足球
Tom 操作给自己点赞
系统提示 -------不能给自己点赞-------点赞失败
游客B浏览到Tom的信息
游客B给Tom点赞
游客B查看Tom的爱好为足球
游客B修改TOM的兴趣为喝酒
系统提示 -------不能对别人做点赞以外的的设置操作-------修改失败
// 动态代理测试类
public class DynamicProxyTest {
public static void main(String[] args) {
ClassLoader loader = PersonImpl.class.getClassLoader();
Class<?>[] interfaces = PersonImpl.class.getInterfaces();
Person person = new PersonImpl();
System.out.println("Tom 登陆");
person.setName("Tom");
// 创建相应的保护代理
Person ownerProxy = getOwnerProxy(loader, interfaces, person);
System.out.println("Tom 设置自己写兴趣为足球");
ownerProxy.setInterests("足球");
try {
System.out.println("Tom 操作给自己点赞");
ownerProxy.setRating();
} catch (Exception e) {
System.out.println("系统提示 -------不能给自己点赞-------点赞失败");
}
System.out.println();
System.out.println("游客B浏览到Tom的信息");
// 创建相应的保护代理
Person nonOwnerProxy = getNonOwnerProxy(loader, interfaces, person);
System.out.println("游客B给Tom点赞");
nonOwnerProxy.setRating();
String interests = nonOwnerProxy.getInterests();
System.out.println("游客B查看Tom的爱好为"+interests);
try {
System.out.println("游客B修改TOM的兴趣为喝酒");
nonOwnerProxy.setInterests("喝酒");
} catch (Exception e) {
System.out.println("系统提示 -------不能对别人做点赞以外的的设置操作-------修改失败");
}
}
private static Person getOwnerProxy(ClassLoader loader, Class<?>[] interfaces, Person person) {
Person ownerPersion = (Person) Proxy.newProxyInstance(loader, interfaces, new OwnerInvocationHandler(person));
return ownerPersion;
}
private static Person getNonOwnerProxy(ClassLoader loader, Class<?>[] interfaces, Person person) {
Person nonOwnerProxy = (Person)Proxy.newProxyInstance(loader, interfaces,
new NonOwnerInvocationHandler(person));
return nonOwnerProxy;
}
static class OwnerInvocationHandler implements InvocationHandler {
private Person person;
public OwnerInvocationHandler(Person person) {
this.person = person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if (methodName.equals("setRating")) {
// 不能给自己打分
throw new IllegalAccessException();
}
return method.invoke(person, args);
}
}
static class NonOwnerInvocationHandler implements InvocationHandler {
private Person person;
public NonOwnerInvocationHandler(Person person) {
this.person = person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
String methodName = method.getName();
if (methodName.startsWith("set") && !methodName.startsWith("setRating")) {
// 不能对别人做点赞以外的的设置操作
throw new IllegalAccessException();
}
return method.invoke(person, args);
}
}
}