1. 程式人生 > >設計模式---結構型---代理模式

設計模式---結構型---代理模式

  1,定義:

          提供了目標物件的另外的訪問方式,即通過代理物件訪問目標物件,就好比生活中的中介,比如你要買房子,房產商就是目標物件,中介就是代理物件,你通過中介買了房子就相當於通過代理物件訪問目標物件,在程式設計中,體現了一種思想,即不要改動別人寫好的功能,而是通過代理物件來擴充套件額外的功能,代理物件又分為三種,分別為靜態代理,動態代理和Cglib代理,下面我們通過程式碼來講述這三種代理。

  2,程式碼實現

    (1)靜態代理:

                靜態代理在使用時,需要定義介面或者父類,被代理物件與代理物件一起實現相同的介面或者是繼承相同父類

      比如下面的例子,dao層定義了一系列的增,刪,改,查,等操作資料庫的方法,其子類有具體的實現,現在我想

      給每個方法都加上日誌輸出功能,這時就可以通過代理物件實現

/**
 * 資料訪問層
 * ceate by hjiang
 */
public interface IUserDAO {
    /**
     * 增
     */
    void save();

    /**
     * 刪
     */
    void delete();

    /**
     * 改
     */
    void update();

    /**
     * 查
     */
    void query();
}
public class UserDaoImpl implements IUserDAO {
    @Override
    public void save() {
        System.out.println("儲存資料.....");
    }

    @Override
    public void delete() {
        System.out.println("刪除資料....");
    }

    @Override
    public void update() {
        System.out.println("修改資料.....");
    }

    @Override
    public void query() {
        System.out.println("查詢資料.....");
    }
}
public class UserDaoProxy implements IUserDAO {

    private static final Logger logger=Logger.getLogger(UserDaoProxy.class);
    private IUserDAO userDAO;

    public UserDaoProxy(IUserDAO userDAO){
        this.userDAO=userDAO;
    }


    @Override
    public void save() {
        logger.info("儲存方法日誌.....");
        userDAO.save();
    }

    @Override
    public void delete() {
        logger.info("刪除方法日誌...");
        userDAO.delete();
    }

    @Override
    public void update() {
        logger.info("修改方法日誌...");
        userDAO.update();
    }

    @Override
    public void query() {
        logger.info("查詢方法日誌...");
        userDAO.query();
    }
}
public class App {

    public static void main(String[] args) {

        UserDaoImpl userDAO=new UserDaoImpl();

       UserDaoProxy proxy=new UserDaoProxy(userDAO);

       proxy.save();
    }
}

 此時就可以通過代理象額外的新增日誌功能,但這樣會有一個缺點,因為代理類需要實現目標介面,所以會有很多的代理類,如果在介面中增加方法,那麼代理類也得改,這樣維護起來不方便,所以會用到下面的動態代理

(2) 動態代理:

         動態代理不需要實現介面,利用JDK的API動態的在記憶體中構建代理物件(需要我們指定建立代理物件/目標物件實現的介面的型別)

public class ProxyFactory {

    private Object object;

    public ProxyFactory(Object object){
        this.object=object;
    }


    /**
     * ClassLoader:類載入器
     * getInterfaces:目標介面物件
     * InvocationHandler:事件處理
     * @return
     */
    public Object getProxyInatance(){

     return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),
                new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("開啟事務....");
                Object obj=method.invoke(object,args);
                System.out.println("結束事務....");
                return obj;
            }
        });
    }
}
public class App {

    public static void main(String[] args) {

      IUserDAO userDAO=new UserDaoImpl();

      IUserDAO proxy=(IUserDAO)new ProxyFactory(userDAO).getProxyInatance();

      proxy.save();
    }
}

  這樣通過動態代理就不用實現介面,也可以動態的在某個方法上增強了,但是有時候目標物件不是一個介面,而是一個單獨的   類,這時動態代理也無法滿足了,此時就需要Cglib代理來實現,Cglib代理,也叫作子類代理,它是在記憶體中構建一個子類物件從而實現對目標物件功能的擴充套件.

  Spring 中用到了cglib代理,所以直接引入Spring得核心包:spring-core-3.2.3.RELEASE.jar

/**
 * Cglib子類代理工廠
 * 對UserDao在記憶體中動態構建一個子類物件
 */
public class CglibProxyFactory implements MethodInterceptor {

    private Object target;

    public CglibProxyFactory(Object target){
        this.target=target;
    }

    /**
     * 給目標物件建立代理物件
     * @return
     */
    public Object getProxyInstance(){
        //工具類
        Enhancer en=new Enhancer();
        //設定父類
        en.setSuperclass(target.getClass());
        //設定回撥函式
        en.setCallback(this);
        //建立子類(代理物件)
        return en.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("開始事務...");
        Object returnValue=method.invoke(target,args);
        System.out.println("提交事務.....");
        return returnValue;
    }
}
public class App {

    public static void main(String[] args) {

     UserDao userDao=new UserDao();

     UserDao proxy=(UserDao)new CglibProxyFactory(userDao).getProxyInstance();

     proxy.save();
    }
}