代理模式的目的
代理模式是一种结构型设计模式,其目的是为了扩展目标对象的功能。
代理模式有三种类型,静态代理,动态代理(JDK代理,接口代理)、Cglib代理(在内存中动态的创建目标对象的子类)
静态代理
静态代理需要先定义接口,被代理对象与代理对象一起实现相同的接口,然后通过调用相同的方法来调用目标对象的方法。
//实体类
public class Tv {
private String name;
private String adress;
public Tv(String name, String adress) {
this.name = name;
this.adress = adress;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
@Override
public String toString() {
return "Tv{" +
"name='" + name + ''' +
", adress='" + adress + ''' +
'}';
}
}
//公司接口
public interface TvCompany {
/**
* 生产电视机
*
* @return
*/
Tv produceTV();
}
//公司生产车间
public class TvFactory implements TvCompany{
@Override
public Tv produceTV() {
return new Tv("华为","北京");
}
}
//代理商
public class TvProxy implements TvCompany {
private TvFactory factory;
@Override
public Tv produceTV() {
if (factory == null) {
factory = new TvFactory();
}
return factory.produceTV();
}
}
//消费者拿到通过代理商拿到商品(代理类的使用)
public static void main(String[] args) {
TvProxy proxy = new TvProxy();
Tv tv = proxy.produceTV();
System.out.println(tv);
}
- 优点:静态代理模式在不改变目标对象的前提下,实现了对目标对象的功能扩展。
- 缺点:静态代理实现了目标对象的所有方法,一旦目标接口增加方法,代理对象和目标对象都要进行相应的修改,增加维护成本。
动态代理
特点:JDK动态代理对象不需要实现接口,只有目标对象需要实现接口。
//接口增加维修功能
public interface TvCompany {
/**
* 生产电视机
*
* @return
*/
Tv produceTV();
/**
* 维修
* @return
*/
Tv repairTV();
}
//工厂增加维修业务
public class TvFactory implements TvCompany {
@Override
public Tv produceTV() {
return new Tv("华为", "北京");
}
@Override
public Tv repairTV() {
return new Tv("小米", "北京");
}
}
//新的代理商代理公司业务
public class TvProxyFactory {
private Object target;
public TvProxyFactory(Object object) {
this.target = object;
}
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("TV proxy find factory for tv.... ");
Object invoke = method.invoke(target, objects);
return invoke;
}
});
}
}
//用户通过代理商完成购买和维修
public static void main(String[] args) {
TvFactory taget = new TvFactory();
TvCompany tvCompany = (TvCompany) new TvProxyFactory(taget).getProxy();
Tv tv = tvCompany.produceTV();
Tv tv1 = tvCompany.repairTV();
System.out.println(tv);
System.out.println(tv1);
}
- 代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理。
- 动态代理的方式中,所有的函数调用最终都会经过 invoke 函数的转发,因此我们就可以在这里做一些自己想做的操作,比如日志系统、事务、拦截器、权限控制等。
Java动态代理只能代理接口,要代理类需要使用第三方的CGLIB等类库