代理设计模式详解(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()生成的对象是一样的。这个才是真正的动态代理类。

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

 

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java设计模式之行为型:策略模式

    Java设计模式之行为型:策略模式

    2021年10月4日
    47
  • 23种设计模式(15):备忘录模式

    23种设计模式(15):备忘录模式

    2021年11月16日
    44
  • java设计模式3,里氏替换原则

    java设计模式3,里氏替换原则里氏替换原则的内容可以描述为:“派生类(子类)对象可以在程序中代替其基类(超类)对象。”

    2025年7月3日
    4
  • Java设计模式——策略模式[通俗易懂]

    Java设计模式——策略模式[通俗易懂]策略模式1.策略模式简介策略模式:策略模式是一种行为型模式,它将对象和行为分开,将行为定义为一个行为接口和具体行为的实现。策略模式最大的特点是行为的变化,行为之间可以相互替换。每个if判断都可以理解为就是一个策略。本模式使得算法可独立于使用它的用户而变化2.模式结构策略模式包含如下角色:Strategy:抽象策略类:策略是一个接口,该接口定义若干个算法标识,即定义了若干个抽象方法(如下图的algorithm())Context:环境类/上下文类:上下文是依赖于接口的类(

    2022年9月9日
    3
  • PHP设计模式-工厂模式[通俗易懂]

    PHP设计模式-工厂模式[通俗易懂]PHP设计模式-工厂模式一、工厂模式概念工厂模式,顾名思义,像工厂的流水线,固定的规格,固定的材料,做固定的事情。工厂模式分为三种:简单工厂、工厂方法、抽象工厂,三种工厂的区别是,抽象工厂由多条产品线,而工厂方法只有一条产品线,是抽象工厂的简化。而工厂方法和简单工厂相对,大家初看起来好像工厂方法增加了许多代码但是实现的功能和简单工厂一样。但本质是,简单工厂并未严格遵循设计模式的开闭原则,当需要增加新产品时也需要修改工厂代码。但是工厂方法则严格遵守开闭原则,模式只负责抽象工厂接口,具体工厂交给客.

    2022年7月25日
    11
  • 十九、原型模式—通过复制生产实例 #和设计模式一起旅行#[通俗易懂]

    拔一根猴毛,变出十万个孙悟空故事背景在java中,我们一般创建实例的时候可以使用了new 关键词指定类名来生成类的实例。例如:Preson p = new Person();或者Person p = Person.getInstance();但是是在实际开发过程中,有时候会有“不指定类名的前提下生成实例”的需求。这种情况下,就不能通过上面的这种方式生成实例!…

    2022年2月27日
    41

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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