设计模式---代理模式

代理模式

  • 在代理模式Proxy Pattern中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
  • 意图:为其他对象提供一种代理,以控制对这个对象的访问。
  • 主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
  • 优点: 1、职责清晰。 2、高扩展性。 3、智能化。
  • 缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
  • 使用场景:按职责来划分,通常有以下使用场景: 远程代理。Cache代理。防火墙(Firewall)代理。
  • 注意事项
    1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
    2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

代理模式可以分为2种:静态代理模式和动态代理模式
静态模式:

这里写图片描述

//目标接口
public interface Image {
   void display();
}

//真实对象
public class RealImage implements Image {真实对象

   private String fileName;

   public RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }

   @Override
   public void display() {
      System.out.println("Displaying " + fileName);
   }

   private void loadFromDisk(String fileName){
      System.out.println("Loading " + fileName);
   }
}

//代理对象
public class ProxyImage implements Image{
	//代理对象中包含具体目标对象
   private RealImage realImage;
   private String fileName;

   public ProxyImage(String fileName){
      this.fileName = fileName;
   }
   @Override
   public void display() {
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.display();
   }
}

//从形式上看调用的是代理对象,不是具体工作的目标对象.
Image image = new ProxyImage("test.jpg");
//图像将从磁盘加载
image.display(); 
System.out.println("");
//图像将无法从磁盘加载
image.display();

缺点:需要目标接口,而且针对一个接口需要一个代理对象,可能会导致类爆炸问题

动态代理
有2种实现方式:

  • 使用JDK的动态代理:要求采用JDK的反射机制实现,必须有对应的接口
  • 使用 CGLib的动态代理:可以没有对应的接口
  • 使用Cglib创建代理的效率略低于JDK动态代理

JDK反射包中的相关接口和工厂类
接口java.lang.reflect.InvocationHandler
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable; }
-proxy - 在其上调用方法的代理实例
-method - 对应于在代理实例上调用的接口方法的 Method 实例
-args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null

Proxy的静态方法newProxyInstance(ClassLoader loader, Class<>[] interfaces,InvocationHandler h)生成代理类
–loader - 定义代理类的类加载器
–interfaces - 代理类要实现的接口列表
–h - 指派方法调用的调用处理程序

案例1:

//目标接口,使用JDK的动态代理必须有对应的目标接口
public interface 歌星 {
	void 唱歌();
}

//具体的目标类,实现目标接口
public class 刘德华 implements 歌星 {
	@Override
	public void 唱歌() {
		System.out.println("冷冷的冰雨,在脸上胡乱的拍~~~");
	}
}

//代理的回调处理类,不是具体的代理类,使用动态代理时没有具体的代理类
public class 宋喆的回调处理类 implements InvocationHandler {// 调用宋喆的任何方法实际上都是回调类对象处理
	private Object target;
	public 宋喆的回调处理类(Object target) {
		this.target = target;
	}
	
//调用代理对象的任何方法时,实际上就是执行这个回调方法,这里可以添加对应的判断,判断执行的是什么方法,例如唱歌方法或者演电影方法:arg1.getName():String获取方法名称
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {

		// 由代理对象限制目标对象的访问
		System.out.println("签订演艺合同......");
		Object res = arg1.invoke(target, arg2);
		System.out.println("收钱收钱~~~~~~~");
		return res;
	}
}
//调用处不能直接生成代理对象,因为没有具体的代理类定义,代理对象需要依赖于反射包中的Proxy工具类生成。
歌星.class.getClassLoader()用于获取加载歌星接口定义的类加载器

	歌星 proxy = (歌星) Proxy.newProxyInstance(歌星.class.getClassLoader(), new Class[] { 歌星.class, 影星.class这里定义所有可以代理的接口 },new 宋喆的回调处理类(new 刘德华()));// 动态创建一个对象对象,这个对象没有对应的类定义
proxy.唱歌();

案例2:

//接口
public interface 歌星 {public void 唱歌();}

//具体的实现
public class 汪峰 implements 歌星 {
	@Override
	public void 唱歌() {System.out.println("北京~北京~~~");	}
}

//没有对应的代理类,只有通过实现接口定义的代理回调处理类,调用代理对象的任何方法实际上都是执行invoke方法

public class 宋喆的回调处理类 implements InvocationHandler {
	private Object 被代理对象;//这里的被代理对象使用Object进行定义,就是说可以代理任何对象,没有接口的束缚
	public 宋喆的回调处理类(Object target){this.被代理对象=target;	}
	@Override
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
	System.out.println("签演艺合同!!!!!");
		Object res=method.invoke(被代理对象, args);  //意思是调用被代理对象的同名方法,并且传入参数args
	System.out.println("收钱``````");
	return res;	}
}

//测试
歌星 obj = new 汪峰();
歌星 宋喆= (歌星) Proxy.newProxyInstance(歌星.class.getClassLoader(), new Class[] { 歌星.class }, new 宋喆的回调处理类(obj)); // 实际上是通过宋喆访问汪峰,由宋喆控制对汪峰的访问,这就是代理模式的核心
宋喆.唱歌();  //调用宋喆代理对象的任何方法实际上都是执行代理回调处理类中的invoke方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值