代理设计模式详解(java版本)

代理设计模式详解(java版本)

今天给大家详细的介绍一下23中常用的设计模式中的代理设计模式,代理模式分为两种,分别为静态代理和动态代理。

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

解析:

1,其他对象:目标对象,想要访问的对象,常被称为被委托对象或被代理对象。

2,提供一种代理:这里”一种”两个字比较重要,为什么不是提供一个呢?一种代表了某一类,即代理类和被 代理类必须实现同一接口,这个接口下的所有实现类都能被代理访问到,其实只是单纯的为了 实现代理访问功能,代理类不实现任何接口也能完成,不过针对于面向接口的编程,这种方式 更易于维护和扩展,代理类实现接口,不管目标对象怎么改或改成谁,代理类不需要任何修改 ,而且任何目标对象能使用的地方都能用代理去替换。

3,通过代理访问目标对象:代理类需要持有目标对象的引用,这样用户可以通过代理类访问目标对象,实现 了用户与目标对象的解耦。

4,为什么要通过代理来访问:设计模式都是为了解决某一类的问题,可能目标对象不想让该用户访问或者是 该用户无法访问到目标对象,这样就需要一个第三者来建立他们的联系。

5,代理类功能增强(思考装饰设计模式的思想):代理对象能直接访问到目标对象,这样它就能在调用目标对象的某个方法之前做一个预 处理,在调用方法之后进行一些结尾工作,这样就对目标对象的方法进行了增强,但是这并不是代理模式的核心思想。

先讲一个真实场景,博主在的一家公司代理打印机产品,于是找到了一家做打印机的公司(Postek),然后将打印机卖给百丽集团,我们就成了代理者,postek成了被代理者。

1,先看一下这个例子的uml图

代理设计模式详解(java版本)

这个新版的staruml不太会用,实现怎么成了直线了。画的太丑了…PostekProxy的salePrinter()方法,其实是调用了PostekCompany的salePrinter()方法

2,PostekCompany和PostekCompanyProxy有共同的方法salePrinter(),就是都出售打印机,根据uml图编写代码如下:

IProxy.java

package proxy;

public interface IProxy {

	void salePrinter();
}

PostekCompany.java

package proxy;

public class PostekCompany implements IProxy{

	@Override
	public void salePrinter() {
		// TODO Auto-generated method stub
		System.out.println("postek sale printer");
	}

}

PostekCompanyProxy.java

package proxy;

public class PostekCompanyProxy implements IProxy {

	private PostekCompany mPostekCompany;
	
	public PostekCompanyProxy() {
		// TODO Auto-generated constructor stub
		mPostekCompany = new PostekCompany();//控制对象的访问
	}
	//这个方法就是我们公司代理出售打印机的代理方法,也就是最终由我们面向客户,
	//可能客户并不知道打印机最终是由谁生产的,
	@Override
	public void salePrinter() {
		// TODO Auto-generated method stub
		//我们可以直接出售打印机,当然我们也可以做一些自己的事情
		//第一件事情,当然我们得赚差价了,要不然做代理干啥
		System.out.println("赚100块钱");
		//当然还可以做一些其他的事情,就是比如可能改打印机的logo啊,
		System.out.println("修改打印机的logo");
		//出售打印机
		mPostekCompany.salePrinter();//当然最终打印机还是得由博思得来真正的出售啦
		//我们赚了钱,当然要提供服务了,比如7*24小时在线解决打印机问题,这样才能长久嘛
		System.out.println("提供7*24小时处理打印机问题");
	}

}

ProxyClient.java

package proxy;

public class ProxyClient {

	public static void main(String[] args) {
		//直接面向客户卖打印机,客户根本不知道真正生产打印机的地方
		//这里是区别静态代理模式和装饰设计模式很重要的一个地方
		PostekCompanyProxy proxy = new PostekCompanyProxy();
		proxy.salePrinter();
	}
}

运行结果:

代理设计模式详解(java版本)

静态代理非常简单,我们来看下动态代理,动态代理有两种实现方式,一种是JDK自带,一种是CGLIB,使用上其实差不多,分别来看一下。

动态代理有两个非常重要的接口(InvocationHandler)和类(Proxy)。

Proxy主要使用newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)于生成动态代理的对象我看来看下这个方法以及参数的描述

newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序这个指定的调用处理程序就是第三个参数InvocationHandler中的invoke()方法,等下再讲

参数:

loader – 定义代理类的类加载器

interfaces – 代理类要实现的接口列表

h – 指派方法调用的调用处理程序

InvocationHandler:主要是当动态代理类调用代理的方法的时候,其实运行的是该类中的invoke()方法。

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

功能:在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。

参数:

proxy – 在其上调用方法的代理实例

method – 对应于在代理实例上调用的接口方法的 Method 实例。 Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。

args – 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。

接下来通过代码分析如何使用:

IDynamicProxy.java

package dynamicproxy;

public interface IDynamicProxy {
	void salePrinter();
}

PostekCompany.java

package dynamicproxy;

public class PostekCompany implements IDynamicProxy {

	@Override
	public void salePrinter() {
		// TODO Auto-generated method stub
		System.out.println("postek sale printer");
	}

}

DynamicProxyHandler.java

package dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicProxyHandler implements InvocationHandler{

	private Object mObj;//需要代理的对象
	public  DynamicProxyHandler(Object obj) {
		// TODO Auto-generated constructor stub
		this.mObj = obj;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("proxy = "+proxy.getClass().getName());
		System.out.println("赚钱100");
		method.invoke(this.mObj, args);
		System.out.println("提供很好的服务");
		return null;
	}

}

DynamicClient.java

package dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class DynamicClient {

	public static void main(String[] args) {
		IDynamicProxy iProxy = new PostekCompany();
		//IDynamicProxy iProxy = new DSCompany();
		InvocationHandler handler = new DynamicProxyHandler(iProxy);
		IDynamicProxy iDynamicProxy = (IDynamicProxy)Proxy
										 
                                   .newProxyInstance(handler.getClass().getClassLoader(),
								    iProxy.getClass().getInterfaces() ,
									handler);
//上述代码为什么能够转换成IDynamicProxy,这是因为newProxyInstance方法的第二个参数,
//要求生成的代理类实现了IDynamicProxy接口
		System.out.println("iDynamicProxy = "+iDynamicProxy.getClass().getName());
		iDynamicProxy.salePrinter();
	}
}

打印结果:

 代理设计模式详解(java版本)

这是一个简单的动态代理的例子,细心的朋友可能看到控制台中打印的$Proxy0是啥,这个其实是代码在运行时期动态生成的代理对象。有些博客上面描述InvocationHandler的实现类是动态的代理类,其实并不是这样子的,我们在InvocationHandler中的invoke()方法中打印了第一个参数,观察第一个参数的返回值和DynamicClient中的生成的Proxy.newProxyInstance()生成的对象是一样的。这个才是真正的动态代理类。

好了关于代理模式暂时写到这里吧,后面有时间另外再更新!如有不正确的地方欢迎指正

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/111245.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号