代理模式的簡單理解與使用

代理模式

代理模式中存在代理者和被代理者,代理者和被代理者都具備相同的功能,而且代理者執行功能時會附加一些額外的操做java

如:手機工廠和代理商都具備賣東西的功能,手機代理商除了幫工廠賣手機外,還能在賣手機前打廣告推銷,賣手機後還能夠進行售後服務。編程

代理模式的優勢:this

  • 符合開閉原則,不用修改被代理者任何的代碼,就能擴展新的功能編碼

  • 項目的擴展和維護比較方便代理

一、靜態代理

角色分析:調試

  • 抽象角色:通常使用接口或抽象類解決
  • 真實角色:被代理的角色
  • 代理角色:代理真實角色,代理真實角色後,通常會作一些附屬操做
  • 客戶:訪問代理對象的人

這裏使用一個租房中介的案例:code

  • 抽象角色(接口):租房對象

    //租房
    public interface Rent {
        void rent();
    }
  • 真實角色:房東blog

    //房東
    public class Host implements Rent{
    
        public void rent() {
            System.out.println("房東要出租房");
        }
    }
  • 代理角色:中介所(一般包含附屬的一些其餘方法)繼承

    //代理類
    public class Agent implements Rent{
    
        //組合因爲繼承
        private Host host;
    
        public void setHost(Host host) {
            this.host = host;
        }
    
        public void rent(){
            host.rent();
            this.sign();
            this.fare();
        }
    
        //籤合同
        public void sign(){
            System.out.println("中介籤合同");
        }
    
        //中介費
        public void fare(){
            System.out.println("收取中介費");
        }
    }
  • 客戶端訪問代理角色:

    public class Client {
    
        public static void main(String[] args) {
            Host host = new Host();
    
            Agent agent = new Agent();
            agent.setHost(host);
            
            agent.rent();
        }
    
    }

靜態代理模式的好處:

  • 可使真實角色的操做更加純粹,不用關注一些公共的業務
  • 公共業務就交給了代理角色,實現了業務的分工
  • 公共業務發生拓展的時候,方便集中管理

缺點:

  • 靜態代理只能適合一種業務,若是有新的業務,就必須建立新的接口和新的代理

  • 每一個真實角色就會產生一個代理角色,代碼量會翻倍;

AOP(面向切面編程)的實現原理就是代理模式:

1.對於切面織入的實現就是對業務接口建立了一個代理類,

2.代理類中組合了業務接口的實現類,

3.代理類在原先實現類的方法上添加了一些附屬方法,

4.客戶端訪問時即能使用代理類的業務(包括初始業務以及拓展業務)。

這樣就實現了對切面的織入,不須要改變原有代碼而拓展了新的業務,符合開閉原則;

二、動態代理

  • 動態代理的實現基於反射機制

  • 角色和靜態代理相同

  • 動態代理的代理類是動態生成的,而不是直接寫好的

  • 動態代理分爲兩大類:基於接口的動態代理;基於類的動態代理

    • 基於接口:JDK動態代理
    • 基於類:cglib
    • java字節碼實現:javasist

須要瞭解兩個類:

  • Proxy:代理

    • Proxy提供了建立動態代理類和實例的靜態方法,它也是由這些方法建立的全部動態代理類的超類。
  • InvocationHandler接口:調用處理程序

    • InvocationHandler是由代理實例的調用處理程序實現的接口。

      每一個代理實例都有一個關聯的調用處理程序。 當在代理實例上調用方法時,方法調用將被編碼並分派到其調用處理程序的invoke方法。

動態代理的特色:(在靜態代理的基礎上)

  • 一個動態代理類代理的是一個接口,通常就是對應一類業務
  • 一個動態代理類能夠代理多個類,只要這些類實現了同一接口便可

java代碼實現

  • 須要被代理的接口:

    public interface UserService {
        void add();
    
        void delete();
    
        void update();
    
        void query();
    }
  • 真實角色(實現類):

    public class UserServiceImpl implements UserService {
    
        public void add() {
            System.out.println("add");
        }
    
        public void delete() {
            System.out.println("delete");
        }
    
        public void update() {
            System.out.println("update");
        }
    
        public void query() {
            System.out.println("query");
        }
    }
  • 生成代理對象的調試處理類:

    //這個類用於自動生成代理類
    public class ProxyInvocationHandler implements InvocationHandler {
    
        //被代理的接口
        private Object target;
    
        public void setUserService(UserService userService) {
            this.target = userService;
        }
    
        //生成獲得代理類
        public Object getProxy(){
            return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
        }
    
        //處理代理實例,返回結果
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //經過反射獲得調用的方法名
            log(method.getName());
            //調用方法
            return method.invoke(target,args);
        }
    
        //代理類的一些附屬方法
        public void log(String s){
            System.out.println("調用了"+s+"方法");
        }
    }
  • 客戶端:

    public class Client {
    
        public static void main(String[] args) {
            //真實類
            UserServiceImpl userService = new UserServiceImpl();
    
            //動態生成代理角色的處理類
            ProxyInvocationHandler pih = new ProxyInvocationHandler();
            //設置要代理的對象
            pih.setUserService(userService);
            //生成代理實例
            UserService proxy = (UserService) pih.getProxy();
    		
            // **當調用被代理角色的方法時,會經過反射機制調用代理類中的invoke方法
            proxy.query();
    
        }
    }
  • 運行結果:

    調用了query方法
    query

重點:代理對象必須是接口,以及proxy返回的也是接口的代理實例!!

相關文章
相關標籤/搜索