设计模式之代理模式

读书笔记:headfirst 设计模式 ,大话设计模式


代理模式概念

代理模式:为其他对象提供一种代理以控制对这个对象的访问

代理模式式结构图

image

结构代码
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 :远程方法调用
image

虚拟代理

虚拟代理:
作为创建开销大的对象的代表,虚拟代理经常知道我们真正需要一个对象的时候才去创建它,
当对象创建前后创建中时,由虚拟代理来扮演对象的替身
对象创建后,代理就会请求直接委托给对象

image

保护代理

使用javaAPI的动态代理来实现保护代理案例

动态代理

javaAPI中,在运行时动态的创建代理类,实现一个或多个接口,并将方法的调用转发到你所指定的类

image

案例需求

用户信息,用户自己可以设置修改自己的姓名,兴趣,但是不能给自己点赞,
其他用户可以给别人点赞,但是不能修改别人的姓名和兴趣,
利用动态代理创建保护代理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);

		}
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值