首页 > 技术文章 > 设计模式——代理模式

maoan 2013-10-04 16:17 原文

一、引言

  前些天,广州恒大在亚冠赛地上创造了中国足球历史,以8:1比分挺进决赛。虽然我不怎么看足球,毕竟中国的足球,你都知道的啦,但还是挺为恒大感到骄傲,希望恒大能如愿的拿到冠军.....今天我将以亚冠买门票为题引出我今天想写的代理模式吧。

二、代理模式定义

  1. 定义:代理模式也叫委托模式,代理模式为另一个对象提供一个替身或点位符以控制对这个对象的访问。

  2. 类图:【如下图所示】

  3. 类图说明

    客户端与RealSubject交互时都必须通过Proxy。因为Proxy和RealSubject实现相同的接口(Subject),所以任何使用到RealSubject的地方,都可以用Proxy取代。同时Proxy也控制了对RealSubject的访问,如本例中,before()及after()的使用。

三、代理模式示例

  1. Subject

package com.pattern.proxy.core;

/**
 * 球迷接口
 * @author yemaoan
 *
 */
public interface IFans {

    void buyTicket();
}

  2. RealSubject

package com.pattern.proxy.core;

/**
 * 球迷买票
 * @author yemaoan
 *
 */
public class Fans implements IFans {

    private String name;
    
    public Fans(String name) {
        this.name = name;
    }
    
    public void buyTicket() {
        System.out.println(this.name + " 购买门票...");
    }

}

  3. Proxy

package com.pattern.proxy.core;

/**
 * 售票点
 * @author yemaoan
 *
 */
public class Wicket implements IFans {

    private IFans fans;
    
    public Wicket(IFans fans) {
        this.fans = fans;
    }
    
    public void buyTicket() {
        this.before();            //Spring AOP【Before Advice】
        this.fans.buyTicket();    //Joinpoint
        this.after();            //Spring AOP【After Advice】
    }
    
    private void before() {
        System.out.println("准备去售票点购买球票...");
    }

    private void after() {
        System.out.println("买到票啦,让我们一睹恒大夺冠吧...");
    }
}

  4. Junit Test

package com.pattern.proxy.test;

import org.junit.Test;

import com.pattern.proxy.core.Fans;
import com.pattern.proxy.core.IFans;
import com.pattern.proxy.core.Wicket;

public class TestFans {

    @Test
    public void testGetReport() {
        IFans fans = new Fans("swyma");
        Wicket wicket = new Wicket(fans);
        wicket.buyTicket();
    }
}

四、代理模式扩展——动态代理

  1. 定义:动态代理是在实现阶段不用关心谁,而在运行阶段才指定代理哪一个对象。Spring AOP核心也就是采用了动态代理机制。

  2. 执行过程:【如下图所示】

  3. 示例【模仿Spring AOP】

    3.1 DynamicProxy

package com.pattern.proxy.core;

public interface DynamicProxy<T> {

    T newProxyInstace(IFans fans);
}
package com.pattern.proxy.core;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 
 * @author yemaoan
 *
 * @param <T>
 */
public class FansDynamicProxy<T extends Object> implements DynamicProxy<T> {
    
    @Override
    public T newProxyInstace(IFans fans) {
        ClassLoader loader = fans.getClass().getClassLoader();
        Class<?>[] interfaces = fans.getClass().getInterfaces();
        InvocationHandler handler = new FansInvocatioHandler(fans);
        return (T) Proxy.newProxyInstance(loader, interfaces, handler);
    }

    
}

    3.2 InvocationHandler

package com.pattern.proxy.core;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import com.spring.aop.adivce.AdviceFactory;
import com.spring.aop.adivce.AfterAdvice;
import com.spring.aop.adivce.BeforeAdvice;

/**
 * 
 * @author yemaoan
 *
 */
public class FansInvocatioHandler implements InvocationHandler {

    private Object target = null;
    
    /**
     * 
     * @param target 被代理的对象
     */
    public FansInvocatioHandler(Object target) {
        this.target = target;
    }
    
    @Override
    /**
     * @param proxy 被代理对象
     * @param method 调用的方法
     * @param args 方法调用时所需要的参数
     */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        
        Object result = null;
        
        if(method.getName().equals("buyTicket")) {
            AdviceFactory.getAdvice(BeforeAdvice.class).handle();
            result = method.invoke(this.target, args);
            AdviceFactory.getAdvice(AfterAdvice.class).handle();
        }
        
        return result;
    }
    

}

    3.3 模仿Spring AOP示例

package com.spring.aop.adivce;

/**
 * Adivce
 * @author yemaoan
 *
 */
public interface IAdvice {

    void handle();
    
}
package com.spring.aop.adivce;

/**
 * BeforeAdvice
 * @author yemaoan
 *
 */
public class BeforeAdvice implements IAdvice {

    @Override
    public void handle() {
        System.out.println("Spring AOP --> 前置通知");
    }

}
package com.spring.aop.adivce;

/**
 * After Advice
 * @author yemaoan
 *
 */
public class AfterAdvice implements IAdvice {

    @Override
    public void handle() {
        System.out.println("Spring AOP --> 后置通知");
    }

}
package com.spring.aop.adivce;

/**
 * Advice工厂类
 * @author yemaoan
 *
 */
public class AdviceFactory {

    public static <T extends IAdvice> IAdvice getAdvice(Class<T> cls) {
        IAdvice advice = null;
        try {
            advice = (IAdvice) Class.forName(cls.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return advice;
    }
}

    3.4 测试代码

package com.pattern.proxy.test;

import com.pattern.proxy.core.Fans;
import com.pattern.proxy.core.FansDynamicProxy;
import com.pattern.proxy.core.IFans;

public class TestDynamic {

    public static void main(String[] args) {
        IFans fans = new Fans("summer");
        IFans proxy = (IFans) new FansDynamicProxy().newProxyInstace(fans);
        proxy.buyTicket();
    }
}

五、总结

  1. 本文是针对设计模式中的代理模式进行总结及梳理,并结合Spring AOP对Java JDK动态代理进行阐述。

六、题外话

  经过三天三夜在颠簸的路途骑行,好友乃哥终于抵达厦门,以他的话来说就是各种心酸,各种坚持,确实挺不容易的。我暂且不说这种行为该不该提倡,但是这种坚持,这份毅力确实是值得我们尊敬。

推荐阅读