代理模式是设计模式中非常重要的一种类型。代理模式从类型上来说,可以分为静态代理和动态代理两种类型。
假设一个场景,有一个蛋糕店,卖的蛋糕都是用蛋糕机做的,而且不同种类的蛋糕由不同的蛋糕机来做,有水果蛋糕机,巧克力蛋糕机等。它们卖的面包片也是面包机做的,不同种类的面包机也是由不同的面包机来做,有红豆面包机,葡萄干面包机等。用代码描述如下。
//做蛋糕的机器
public interface CakeMachine{
void makeCake();
}
//专门做水果蛋糕的机器
class FruitCakeMachine implements CakeMachine{
public void makeCake() {
System.out.println("Making a fruit cake...");
}
}
//专门做巧克力蛋糕的机器
public class ChocolateCakeMachine implements CakeMachine{
public void makeCake() {
System.out.printf("making a Chocolate Cake...");
}
}
//做面包的机器
public interface BreadMachine {
void makeBread();
}
//专门做红豆面包的机器
public class RedBeanBreadMachine implements BreadMachine {
public void makeBread() {
System.out.println("making red bean bread....");
}
}
//专门做葡萄干面包的机器
public class CurrantBreadMachine implements BreadMachine{
public void makeBread() {
System.out.println("making currant bread...");
}
}
//蛋糕店
public class CakeShop {
public static void main(String[] args) {
new FruitCakeMachine().makeCake();
new ChocolateCakeMachine().makeCake();
new RedBeanBreadMachine().makeBread();
new CurrantBreadMachine().makeBread();
}
}
}
如果有个客户想要在水果蛋糕上面加珍珠,我们可以再做一个水果珍珠蛋糕机,但是这样成本太高,因为不能因为一个客户的请求就造一个新蛋糕机。根据修改封闭,扩展开放原则。我们可以设计一个珍珠代理类(BoboCakeProxy),先用水果蛋糕机做一个水果蛋糕,然后再加上珍珠就好了。
静态代理:
public class BoboCakeProxy implements CakeMachine{
private CakeMachine cakemachine;
public BoboCakeProxy(CakeMachine cakemachine){
this.cakemachine=cakemachine;
}
@Override
public void makeCake() {
cakemachine.makeCake();
System.out.println("add bobo");
}
}
//蛋糕店
public class CakeShop {
public static void main(String[] args) {
//可以给各种各样的蛋糕加上杏仁
FruitCakeMachine fruitCakeMachine = new FruitCakeMachine();
BoboCakeProxy boboCakeProxy = new BoboCakeProxy(fruitCakeMachine);
boboCakeProxy.makeCake();
boboCakeProxy = new BoboCakeProxy(new ChocolateCakeMachine());
boboCakeProxy.makeCake();
}
}
动态代理:
我们只能为一种产品加上珍珠,如果要给面包加珍珠,就需要重新写一个珍珠面包代理,如果产品有100种,那么就得写100个代理类。所以要用动态代理,可以让我们只写一次实现,但是任何类型的产品都可以使用。InvocationHandler。动态代理和静态代理的区别就是静态代理只能针对特定一种产品做代理动作,而动态代理可以针对所有类型产品做代理。写一个珍珠动态代理。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class BoboHandler implements InvocationHandler{
private Object object;
public BoboHandler(Object object){
this.object=object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result=method.invoke(object, args);//调用真正的蛋糕机做蛋糕
System.out.println("add bobo");
return result;
}
}
蛋糕店开始工作
public class CakeShop {
public static void main(String[] args) {
//动态代理(可以同时给蛋糕、面包等加珍珠)
//给蛋糕加上珍珠
FruitCakeMachine fruitCakeMachine = new FruitCakeMachine();
BoboHandler boboHandler = new BoboHandler(fruitCakeMachine);
CakeMachine cakeMachine = (CakeMachine) Proxy.newProxyInstance(fruitCakeMachine.getClass().getClassLoader(), fruitCakeMachine.getClass().getInterfaces(), boboHandler);
cakeMachine.makeCake();
//给面包加上珍珠
RedBeanBreadMachine redBeanBreadMachine = new RedBeanBreadMachine();
boboHandler = new BoboHandler(redBeanBreadMachine);
BreadMachine breadMachine = (BreadMachine) Proxy.newProxyInstance(redBeanBreadMachine.getClass().getClassLoader(), redBeanBreadMachine.getClass().getInterfaces(), boboHandler);
breadMachine.makeBread();
}
}
}
静态代理只能针对某一接口(面包 或 蛋糕)进行操作,如果要对所有接口都(所有产品)都能做一样操作,那就必须要动态代理出马了。
动态代理的几种实现方式
-
Java动态代理
-
CGLib
Java动态代理适合有接口抽象的类代理,而CGLib适合没有接口对象的类代理。
CGLib实现方式
Java动态代理只能针对有接口的类进行扩展,CGLib是使用继承原有类的方式来实现代理的。要是用CGLib来实现以上功能就是,先写一个珍珠拦截器类。
public class BoboInterceptor implements methodInterceptor{
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
methodProxy.invokeSuper(o, objects);
System.out.println("adding bobo...");
return o;
}
}
然后蛋糕店通过调用拦截器类来进行加珍珠操作。
public class CakeShop {
public static void main(String[] args) {
//CGLib动态代理(可以同时给蛋糕、面包等加杏仁)
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(FruitCakeMachine.class);
enhancer.setCallback(new BoboInterceptor());
FruitCakeMachine fruitCakeMachine = (FruitCakeMachine) enhancer.create();
fruitCakeMachine.makeCake();
}
}
}
enhancer.setSuperClass()设置需要增强的类,enhancer.setCallback()设置需要回调的拦截器,也就是实现了MethodInterceptor的接口的类。最后使用enhancer.create()生成了对应的增强类。