结构型模式有七种:
代理模式
代理模式(Proxy Design Pattern)的原理和代码实现都不难掌握。它在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能,为其它对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
角色
优缺点
类图
![](https://i-blog.csdnimg.cn/blog_migrate/4cbfdfc984c5f596dae1b1de3ff40c7a.png)
代码实现
package com.sun.proxy;
/**
* 被代理抽象
* @author work
*
*/
public interface GiveGift {
void GiveDolls();
void GiveFlowers();
void GiveChocolate();
}
package com.sun.proxy;
/**
* 被代理对象
* 真实角色
* @author work
*
*/
public class Pursuit implements GiveGift{
@Override
public void GiveDolls() {
System.out.println("wawa");
}
@Override
public void GiveFlowers() {
System.out.println("flowers");
}
@Override
public void GiveChocolate() {
System.out.println("chocolate");
}
}
package com.sun.proxy;
/**
* 代理对象
* @author work
*
*/
public class Proxy implements GiveGift{
private GiveGift giveGift;
public Proxy(GiveGift giveGift) {
super();
this.giveGift = giveGift;
}
@Override
public void GiveDolls() {
// TODO Auto-generated method stub
giveGift.GiveDolls();
}
@Override
public void GiveFlowers() {
// TODO Auto-generated method stub
giveGift.GiveFlowers();
}
@Override
public void GiveChocolate() {
// TODO Auto-generated method stub
giveGift.GiveChocolate();
}
public static void main(String[] args) {
GiveGift gg = new Pursuit();
Proxy proxy = new Proxy(gg);
proxy.GiveChocolate();
proxy.GiveChocolate();
proxy.GiveDolls();
}
}
上述代码是根据原始类实现了接口的情况下,如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的(比如它来自一个第三方的类库),我们也没办法直接修改原始类,给它重新定义一个接口。在这种情况下,对于这种外部类的扩展,我们一般都是采用继承的方式。我们让代理类继承原始类,然后扩展附加功能。
/**
* 被代理对象
**/
public class Pursuit {
public void GiveDolls() {
System.out.println("wawa");
}
public void GiveFlowers() {
System.out.println("flowers");
}
public void GiveChocolate() {
System.out.println("chocolate");
}
}
/**
* 代理对象
**/
public class ProxyPursuit extends Pursuit{
public void GiveDolls() {
System.out.println("---start GiveDolls---");
super.GiveDolls();
System.out.println("---start GiveDolls---");
}
public void GiveFlowers() {
System.out.println("---start GiveFlowers---");
super.GiveFlowers();
System.out.println("---start GiveFlowers---");
}
public void GiveChocolate() {
System.out.println("---start GiveChocolate---");
super.GiveChocolate();
System.out.println("---start GiveChocolate---");
}
}
上述的代码实现还是有点问题。我们需要在代理类中,将原始类中的所有的方法,都重新实现一遍,并且为每个方法都附加相似的代码逻辑。如果要添加的附加功能的类有不止一个,我们需要针对每个类都创建一个代理类。如果有 100 个要添加附加功能的原始类,那我们就要创建 100 个对应的代理类。这会导致项目中类的个数成倍增加,增加了代码维护成本。并且,每个代理类中的代码都有点像模板式的“重复”代码,也增加了不必要的开发成本。我们可以使用动态代理来解决这个问题。所谓动态代理(Dynamic Proxy),就是我们不为每个原始类编写代理类,而是在运行的时候,动态地创建原始类对应的代理类,然后在系统中用代理类替换掉原始类。jdk本身提供了对动态代理的支持,其本质使用反射来实现,JDK动态代理是基于接口的实现
public interface GiveGift {
void GiveDolls();
void GiveFlowers();
void GiveChocolate();
}
public class Pursuit implements GiveGift{
public void GiveDolls() {
System.out.println("wawa");
}
public void GiveFlowers() {
System.out.println("flowers");
}
public void GiveChocolate() {
System.out.println("chocolate");
}
}
public class ProxyPursuitDynamic {
public static Object createProxy(Object obj) {
Class<?> [] classes = obj.getClass().getInterfaces();
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),classes,new LogInvocationHandler(obj));
}
public static void main(String[] args) {
Pursuit pursuit = new Pursuit();
GiveGift giveGift = (GiveGift) createProxy(pursuit);
giveGift.GiveDolls();
}
}
上述代码是根据原始类实现了接口的情况下,如果原始类并没有定义接口,我们需要使用CGLB代理,CGLB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。代码如下:
public class Pursuit {
public void GiveDolls() {
System.out.println("wawa");
}
public void GiveFlowers() {
System.out.println("flowers");
}
public void GiveChocolate() {
System.out.println("chocolate");
}
}
public class PursuitMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
System.out.println("---start---" );
Object result = proxy.invokeSuper(obj, objects);
System.out.println("---end---" );
return result;
}
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Pursuit.class);
enhancer.setCallback(new PursuitMethodInterceptor());
Pursuit pursuit = (Pursuit)enhancer.create();
pursuit.GiveDolls();
}
}