其实我一直在想,为什么前辈要在java中引入这么多的模式,什么原子模式,组合模式…,虽然这个问题我一直没想得多透彻,但是总归这些模式都会帮助我们解决很多同步异步问题和用简单明了的方法实现更多的功能。
看了很多大神们写的代理模式的说明,在此,我想更加通俗的来阐述一下。
首先有一个问题,我们为啥要在众多的模式中选择代理模式,什么情况下使用代理模式?
代理模式:为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式分为:静态代理模式和动态代理模式
简单的代理模式(静态代理模式):
核心:所有辅助性操作。
一个接口有两个子类,一个负责真实业务,一个负责与真实业务有关的。
所以它的设计:有一个核心的操作接口,接口里声明了核心业务。
有一个真实业务类和一个辅助代理类都实现了该接口。
具体代码实现:
import java.lang.reflect.Constructor;
//核心操作的接口
interface ISubject{
public void eat(); //核心业务
}
class RealSubject implements ISubject{
@Override
public void eat() {
System.out.println("早起吃水果");
}
}
class ProxySubject implements ISubject{
private ISubject subject;
public ProxySubject(ISubject subject){
this.subject=subject;
}
public void prepare(){
System.out.println("准备水果");
}
public void aftereat(){
System.out.println("收拾");
}
@Override
public void eat() {
this.prepare();
this.subject.eat(); //真实业务
this.aftereat();
}
}
//工厂类
class Factory {
private Factory() {
}
public static <T> T getInstance(String className) {
T t = null;
try {
t = (T) Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return t;
}
public static <T> T getInstance(String className, Object obj) {
T t = null;
try {
Constructor<?> cs = Class.forName(className).getConstructor(obj.getClass().getInterfaces()[0]);
t = (T) cs.newInstance(obj) ;
} catch (Exception e) {
e.printStackTrace();
}
return t;
}
}
public class TestDemo1 {
public static void main(String[] args) {
ISubject subject =Factory.getInstance("ProxySubject",Factory.getInstance("RealSubject"));
subject.eat();
}
}
观察上述代码的工厂类,发现整体的处理会非常繁琐,使⽤者使⽤起来也很麻烦。
对于以上代码要实现的操作,客户端最多只需要知道关系代理是谁,实际业务是谁即可。
因此将工厂类的方法改为:
public static T getInstance(String proxyClassName, String realClassname)
参数中传入代理和实际业务。
因此将上述代码的工厂类做如下修改:
class Factory {
private Factory() {
}
public static <T> T getInstance(String className) {
T t = null;
try {
t = (T) Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return t;
}
public static <T> T getInstance(String proxyClassName, String realClassname) {
T t = null;
T realObj = getInstance(realClassname);
try {
Constructor<?> cs =
Class.forName(proxyClassName).getConstructor(realObj.getClass().getInterfaces()[0]);
t = (T) cs.newInstance(realObj);
} catch (Exception e) {
e.printStackTrace();
}
return t;
}
}
这种简单的代理设计只能够代理⼀个接⼝的⼦类对象,⽆法代理更多的接⼝⼦类对象。
因此,要想真正使⽤代理设计模式,我们需要引⼊动态代理设计模式
动态代理设计模式的核心:
一个代理类可以代理所有需要被代理的接口的子类对象
动态代理的设计:
辅助代理实现 InvocationHandler 这个接口
这是 动态代理实现的标识接⼝,只有实现此接⼝才具备有动态代理的功能。
该接口中的方法是:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
说明:
invoke方法:调⽤执⾏的⽅法,所有的代理类返回给⽤户的接⼝对象都属于代理对象.
当⽤户执⾏接⼝⽅法的时候所调⽤的实例化对象就是该代理主题动态创建的⼀个接⼝对象.
方法中参数的说明:
(1)proxy:表示被代理的对象信息
(2)method: 返回的是被调⽤的⽅法对象,取得了Method对象则意味着可以使⽤invoke()反射调⽤⽅法.
(3)args:此时调用代理接口的method方法传入的参数
如果要想进⾏对象的绑定,那么就需要使⽤⼀个 java.lang.reflect.Proxy 程序类,这个程序类的功能是可以绑定所有需要绑定的接⼝⼦类对象,而且这些对象都是根据接口自动创建的,该类有一个动态创建绑定对象的方法:
public static Object newProxyInstance(ClassLoader loader,Class<?>
[]interfaces,InvocationHandler h) throws IllegalArgumentException
具体的代码实现:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface ISubject1{
public void eat(String name,int num);
}
class RealSubject1 implements ISubject1{
@Override
public void eat(String name, int num) {
System.out.println("我要吃 "+num + "分量的 "+name) ;
}
}
class ProxySubject1 implements InvocationHandler{
private Object target;
public Object bind(Object target) {
// 保存真实主题对象
this.target = target ;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this) ;
}
public void preHandle() {
System.out.println("[ProxySubject1] ⽅法处理前");
}
public void afterHandle(){
System.out.println("[ProxySubject1] ⽅法处理后");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.preHandle();
Object result=method.invoke(this.target,args);
this.afterHandle();;
return result;
}
}
public class TestDemo2 {
public static void main(String[] args) {
ISubject1 subject =(ISubject1) new ProxySubject1().bind(new RealSubject1()) ;
subject.eat("苹果",1) ;
}
}
完