静态代理、装饰者模式和动态代理
为什么用代理?
有些类不能被修改的,因业务需要需要扩展这个类的功能。使用代理模式,可以基于被代理类不变的前提下,对被代理类的行为进行控制和扩展。
##静态代理
定义接口
//接口,规定了方法
public interface Car {
public abstract void drive();
}
定义被代理类
import domain.Car;
/*
* 被代理类,实现接口
* */
public class Benchi implements Car {
@Override
public void drive() {
System.out.println("启动速度快!");
}
}
定义代理类
/*
* 代理类
* */
public class BenchiProxy implements Car {
private Car benchi;
//在无参构造器中,创建代理对象
public BenchiProxy() {
this.benchi = new Benchi();
}
@Override
public void drive() {
System.out.println("百公里加速5s");
benchi.drive();
}
}
调用
public class benchiTest {
public static void main(String[] args) {
BenchiProxy benchiProxy = new BenchiProxy();
benchiProxy.drive();
}
}
结果
百公里加速5s
启动速度快!
##装饰者模式
定义接口
//接口,规定了方法
public interface Car {
public abstract void drive();
}
定义被装饰类
/*
* 被装饰类,实现接口
* */
public class Benchi implements Car {
@Override
public void drive() {
System.out.println("启动速度快!");
}
}
定义装饰类
/*
* 装饰类
* */
public class BenchiProxy implements Car {
private Car benchi;
//在有参构造器中,创建代理对象
public BenchiProxy(Car benchi) {
this.benchi = benchi;
}
@Override
public void drive() {
System.out.println("百公里加速5s");
benchi.drive();
}
}
调用
public class benchiTest {
public static void main(String[] args) {
Benchi benchi = new Benchi();
BenchiProxy benchiProxy = new BenchiProxy(benchi);
benchiProxy.drive();
}
}
静态代理类和装饰者模式之间的共同点
1.都要实现与目标类相同的业务接口
2.在两个类中都要生命目标对象(被代理对象和被装饰对象)
3.都可以在不修改目标类的前提下增强方法
静态代理类和装饰者模式之间的不同点
1.目的不同:装饰者是为了增强目标对象;静态代理是侧重与保护和隐藏目标对象
2.对于目标对象的获取方式不同
装饰者中目标对象的获取,是通过有参构造器传入;静态代理中,是在无参构造器中之间创建,直接指定了不能改。
3.功能增强的实现这不同。
装饰者模式中存在装饰者基类,其并不能实现增强,而是由具体的装饰者进行增强的,所有其存在着“装饰者链”;
静态代理中,一般不存在父子类的关系,具体的增强就是有代理类实现的,无需其子类完成,所以不存在链的概念。
##动态代理
重点还是在与动态代理的应用和理解上,java为提供了Proxy类帮助实现动态代理,实现起来也很简单。不需要创建代理类,只需要已知被代理类和被代理类的实现接口。
给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用;被代理的对象难以直接获得或者是不想暴露给客户端。
- 不需要在编译的时候把代理类写死,而是在运行时动态的的创建被代理类的代理对象
package com.atguigu.java;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//接口
interface Human{
String getBelief();
void eat(String food);
}
//被代理类
class SuperMan implements Human{
@Override
public String getBelief() {
return "I believe I can fly!";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃" + food);
}
}
class ProxyFactory{
//使用此方法返回一个代理类对象
public static Object getProxyInstance(Object obj){//代理对象
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
myInvocationHandler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),myInvocationHandler);
}
}
class MyInvocationHandler implements InvocationHandler{
//当我们通过代理类的对象,调用方法a时,就会自动的调用如下方法invoke()
//将被代理类要执行的方法a的功能就生命在invoke()中
private Object obj;
public void bind(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
Object returnValue = method.invoke(obj, args);
return returnValue;
}
}
public class ProxyTest {
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
//代理类对象
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
//调用代理类的方法时,内部调用被代理类的方法
proxyInstance.getBelief();
proxyInstance.eat("麻辣烫");
}
}
其中
Proxy.newProxyInstance创建的是ITeacher 对象,其中的参数解释如下:
-
ClassLoader loader,类加载器。被代理类的类加载器。
-
Class<?>[] interfaces,被代理类所实现的接口,这个接口也可以是多个
。
- InvocationHandler
h,绑定代理类方法。代理类每调用一次任一方法,h(InvocationHandler)的invoke方法对应调用一次。