Proxy代理模式

Proxy Pattern(即:代理模式),23種常用的面向對象軟件的設計模式之一
代理模式的定義:爲其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。
優點:

  • 真實的角色就是實現實際的業務邏輯,不用關心其他非本職責的事務,通過後期的代理完成一件完成事務,附帶的結果就是編程簡潔清晰。
  • 代理對象可以在客戶端和目標對象之間起到中介的作用,這樣起到了的作用和保護了目標對象的作用。
  • 高擴展性

一個是真正的你要訪問的對象(目標類),另一個是代理對象,真正對象與代理
對象實現同一個接口,先訪問代理類再訪問真正要訪問的對象。


代理模式的要求:

  1. 代理這和被代理這實現相同的接口
  2. 代理者必須有被代理這的實例(引用)
  3. 代理這調用被代理這的方法

靜態代理:簡單代理
代理者和被代理這需要是實現共同的接口,即我們的裝飾模式
創建一個潘金蓮對象,實現Kindweman接口,同時創建一個代理者王婆也實現這個接口


public class PJL implements  KindWeman{
    @Override
    public void ShowEyes(Double money) {
        System.out.println("PJL 拿到"+money+"元錢,showeyes");

    }
    @Override
    public void DoSe(Double money) {
        System.out.println("PJL 拿到"+money+"元錢,Dose");
    }
}

public class WP implements KindWeman {
    private KindWeman kw = null;


    public WP(KindWeman kw ){
        this.kw = kw;
    }
    @Override
    public void ShowEyes(Double money) {
        kw.ShowEyes(money);
    }

    @Override
    public void DoSe(Double money) {
        kw.DoSe(money);
    }
}

潘金蓮需要王婆的代理,代理者調用的方法都是被代理者的

public static void main(String[] args){
        KindWeman KW = new PJL();
        WP p = new WP(KW);

        p.ShowEyes(3.0);
        p.DoSe(6.0);
    }

動態代理
動態代理它可以直接給某一個目標對象生成一個代理對象,而不需要代理類存在。
動態代理與代理模式原理是一樣的,只是它沒有具體的代理類,直接通過反射生成了一個代理對象。
動態代理生成技術:
1、jdk提供一個Proxy類可以直接給實現接口類的對象直接生成代理對象。
2、cglib (spring框架)

Java.lang.reflect.Proxy類可以直接生成一個代理對象,看例子,這裏不需要王婆這個代理者,jdk給我們提供了。

 @Test
public void test(){
    KindWeman kw = new PJL();
    //創建一個代理對象
    //ClassLoader:類加載器。固定寫法,和被代理類使用相同的類加載器即可。kw.getClass().getClassLoader()
    //Class[] interface:代理類要實現的接口。固定寫法,和被代理類使用相同的接口即可。kw.getClass().getInterfaces()
    //InvocationHandler:策略(方案)設計模式的應用。如何代理?即代理的過程,你需要的操作
    KindWeman KWproxy = (KindWeman) 
    Proxy.newProxyInstance(kw.getClass().getClassLoader(), kw.getClass().getInterfaces(), new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //nvocationHandler中的invoke方法:調用代理類的任何方法,此方法都會執行 
            //Object proxy:代理對象本身的引用。一般用不着。
            //Method method:當前調用的方法。通過反射, KWproxy調用誰,這裏的Method就是誰
            //Object[] args:當前方法用到的參數
            System.out.println("我是中間代理:需要收取費用");
            Object o = method.invoke(kw, new Object[]{(Double) args[0] / 2});
            System.out.println("事務完成,下次再來!");
            return o;
        }
    });
    KWproxy.ShowEyes(6.0);
    KWproxy.ShowEyes(3.0);
}

這裏寫圖片描述
使用這個思想,在我們前面講到的業務層調用ThreadLocal管理,就不必要在servce層面上編寫了。編寫一個類來動態的獲取服務,然後在代理當中添加ThreadLocal類實現事務的功能

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

import com.itheima.service.AccountService;
import com.itheima.service.impl.AccountServiceImpl;

public class ObjectFactory {
    //方法返回一個代理對象
    public static AccountService getAccountService(){
        final AccountService  as= new AccountServiceImpl(); 


        AccountService proxy = (AccountService) Proxy.newProxyInstance(as.getClass().getClassLoader(), as.getClass().getInterfaces(), new InvocationHandler() {

            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                Object invoke = null;
                try {

                    ManagerThreadLocal.startTransacation();//begin
                    //執行的是真實對象的轉賬方法
                    invoke = method.invoke(as, args);

                    ManagerThreadLocal.commit();//提交事務
                } catch (Exception e) {
                    try {
                        ManagerThreadLocal.rollback();//回滾事務
                    } catch (Exception e1) {
                        e1.printStackTrace();
                    } 
                }finally{
                    try {
                        ManagerThreadLocal.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }//關閉
                }
                return invoke;
            }
        });
        return proxy;   
    }
}
public void transfer(String fromname, String toname, double money) throws Exception {
    //  ad.updateAccount(fromname, toname, money);
        AccountDao ad = new AccountDaoImpl();


            //分別得到轉出和轉入賬戶對象
            Account fromAccount = ad.findAccountByName(fromname);
            Account toAccount = ad.findAccountByName(toname);

            //修改賬戶各自的金額
            fromAccount.setMoney(fromAccount.getMoney()-money);
            toAccount.setMoney(toAccount.getMoney()+money);

            //完成轉賬操作
            ad.updateAccout(fromAccount);
        int i = 10/0;
            ad.updateAccout(toAccount);


    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章