代理设计模式
设计模式其实就是如何去合理的进行抽象。
优点:保护真实对象,让 其职能更明确,有扩展性
相关概念:真实对象(老板) 代理对象(秘书) 抽象对象:谈生意,吃饭(抽象功能)
1、静态代理
由代理对象代理所有真实对象的功能,需要自己编写代理类,每个代理的功能需要单独去编写。
缺点:代理真实对象的功能比较多时,对应的方法需要编写很多。
光说没用,上代码!
A、建立抽象对象实现抽象功能(功能接口)
里边有两个抽象方法,吃饭和谈生意。
package pojo;
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 22:03
* @Description:
*/
public interface Gongneng {
void chifan();
void tanshengyi();
}
B、建立真实对象(Boss类)实现Gongneng接口,一个name属性,两个重写的方法,输出控制台语句,非常简单。
package pojo;
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 21:59
* @Description:
*/
public class Boss implements Gongneng {
private String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public Boss() {
}
public Boss(String name) {
this.name = name;
}
@Override
public void chifan() {
System.out.println("共进晚餐");
}
@Override
public void tanshengyi() {
System.out.println("谈个十个亿的小生意");
}
}
C、建立代理类(Mishu类) 秘书类同样去实现Gongneng接口,重写两个抽象方法。
package pojo;
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 22:04
* @Description:
*/
public class Mishu implements Gongneng {
private Boss boss = new Boss("大老板");
@Override
public void chifan() {
System.out.println("先预约下时间吧");
boss.chifan();
System.out.println("登记在册");
}
@Override
public void tanshengyi() {
System.out.println("先预约下时间吧");
boss.tanshengyi();
System.out.println("登记在册");
}
}
D、建立访问对象(我) 测试类看下结果
package pojo;
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 22:06
* @Description:
*/
public class Wo {
public static void main(String[] args){
Mishu mishu = new Mishu();
mishu.chifan();
}
}
E、结果
总结:上边是很简单的代码,很明显有了秘书这个代理类,保护了真实对象大老板,使大老板的职责更加明确,专注于大事。
同样,秘书代理类也实现了扩展的功能,例如:要预约时间、登记在册。
但是,也可以看出,真实对象中每增加一个功能,代理对象都得去再实现一次,造成繁琐,所以就显出动态代理的优点。
2、动态代理
为解决静态代理频繁编写代理类中代码的缺点,提供两种方式。
A、JDK动态代理
优点:JDK自带,不用额外导入Jar包
缺点:真实对象必须实现接口,底层运用反射机制效率低下。
使用时可能造成ClassCastException异常:原因是希望把接口对象转换为具体对象。
代码实例:
1、真实对象不变,跟静态相比区别在代理类;
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 21:59
* @Description:
*/
public class Boss implements Gongneng {
public void chifan() {
System.out.println("共进晚餐");
}
public void tanshengyi() {
System.out.println("谈个十个亿的小生意");
}
}
2、Gongneng接口
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 22:03
* @Description:
*/
public interface Gongneng {
void chifan();
void tanshengyi();
}
3、秘书类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 22:25
* @Description:
*/
public class Mishu implements InvocationHandler {
Boss boss = new Boss();
/**
* 重写invoke方法,三个参数解释如下
* @param proxy 真实对象
* @param method 方法
* @param args 参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("预约时间");
//反射使用method调用具体的方法,boss真实对象传入
Boss result = (Boss) method.invoke(boss, args);
System.out.println("登记在册");
return result;
}
}
4、我 测试类
import java.lang.reflect.Proxy;
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 22:06
* @Description:
*/
public class Wo {
public static void main(String[] args){
Mishu mishu = new Mishu();
Gongneng gongneng = (Gongneng) Proxy.newProxyInstance(Wo.class.getClassLoader(), new Class[]{Gongneng.class}, mishu);
gongneng.chifan();
}
}
5、结果
总结:JDK动态代理的机制是接口调用“谈生意”方法,其实调用的是Proxy代理类,它会自动回调invoke方法,实现接口就可以把Proxy赋给接口。接口.tanshengyi();实际上调Proxy的谈生意,而调Proxy的机制是每次调任意方法之前都要走invoke()方法。这是Java三大特性之一的多态特性。
多态:同一个方法调用,由于对象的不同可能会有不同的行为。而接口毫无疑问可以体现出多态的特性,接口可以多继承,例如超类对象引用 访问 子类对象,类B类C实现接口方法fun(); 通过将类B和类C的实例赋给接口引用A,实现方法运行时动态绑定。
反射时用到类加载器加载类,JVM虚拟机只生成一个。
B、CGLIB动态代理
优点:基于字节码,生成真实对象的子类,运行效率高于JDK动态代理,不用实现接口
缺点:非JDK功能,需要导入额外Jar包
1、导包 cglib asm (字节码解析包)
2、Boss
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 21:59
* @Description:
*/
public class Boss implements Gongneng {
public void chifan() {
System.out.println("共进晚餐");
}
public void tanshengyi() {
System.out.println("谈个十个亿的小生意");
}
}
3、功能
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 22:03
* @Description:
*/
public interface Gongneng {
void chifan();
void tanshengyi();
}
4、秘书
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 22:25
* @Description:
*/
public class Mishu implements MethodInterceptor {
/**
* 重写intercept方法,四个参数
* @param o 子类对象
* @param method 代理的方法
* @param objects 参数
* @param methodProxy 子类重写父类的代理方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("预约时间");
//它俩等效
//method.invoke(o,objects); 调子类重写的方法
//调父类
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("登记在册");
return result;
}
}
5、测试
import net.sf.cglib.proxy.Enhancer;
import java.lang.reflect.Proxy;
/**
* @Auther:jiaxuan
* @Date: 2019/4/2 0002 22:06
* @Description:
*/
public class Wo {
public static void main(String[] args){
Enhancer enhancer = new Enhancer();
//生成Boss类的子类
enhancer.setSuperclass(Boss.class);
//当调Boss类的子类时处理程序为秘书
enhancer.setCallback(new Mishu());
//产生老总对象子类
Boss boss = (Boss) enhancer.create();
boss.tanshengyi();
}
}
6、结果