設計模式-代理模式

個人博客原文鏈接

簡介

  • 給目標對象(被代理對象)提供一個代理對象,並由代理對象控制對目標對象(被代理對象)的引用,代理對象相當於一箇中介。
  • 通過引入代理對象的方式來間接訪問目標對象,防止直接訪問對象給系統帶來不必要的複雜性。
  • 相當於,代理對象擁有被代理對象的所有功能,並且代理對象還添加了額外的功能來控制被代理對象。

靜態代理

代理類與被代理類實現同一個接口,將被代理類組合到代理類中並添加控制操作。
實例:
共同的接口

public interface Sourceable {  
        public void method();  
    }      

被代理類

public class Source implements Sourceable {  

        public void method() {  
            System.out.println("the original method!");  
        }  
    }

代理類

public class Proxy implements Sourceable {  

        private Source source;  
        public Proxy(Source source){  
            this.source = source;  
        }  
        public void method() {  
            before();  
            source.method();  
            atfer();  
        }  
        private void atfer() {  
            System.out.println("after proxy!");  
        }  
        private void before() {  
            System.out.println("before proxy!");  
        }  
}  

測試類

public class ProxyTest {  
        public static void main(String[] args) {  
            Source target = new Source();
            Sourceable proxy = new Proxy(target);  
            proxy.method();  
        }  
    } 

動態代理

設計動態代理類時,不需要顯式實現與被代理類相同的接口,而是將這種實現推遲到程序運行時由JVM來實現。
通過Java反射機制的method.invoke(),通過調用動態代理類對象方法,從而自動調用目標對象的方法。
實例:假設一個系統中有三個簡單角色,”遊客”,”會員”,”管理員”,當用一個用戶User進行查看其它用戶信息功能showUsersInfo的時候,但是隻有管理員纔能有權限使用這個功能。
用戶類

public class User {
    String name;
    String id;

    public User(String name, String id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "User{" +
                "namae='" + name + '\'' +
                ", id='" + id + '\'' +
                '}';
    }
}

用戶操作接口

public interface UserService {
    public void showUsersInfo(User user);
}

用戶操作類(被代理類)

public class UserServiceIpm implements UserService {
    private User user;

    public UserServiceIpm(User user) {
        this.user = user;
    }

    @Override
    public void showUsersInfo(User user) {
        System.out.println(user);
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

用戶操作代理類(代理類)

public class UserServiceProxy implements InvocationHandler{
    private Object target; //被代理對象

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理");
        target = (UserServiceIpm)target;
        String name = ((UserServiceIpm) target).getUser().name;
        if (name=="管理員"){
            Object o = method.invoke(target,args);
            return o;
        }else{
            System.out.println("沒有權限");
            return null;
        }
    }
}

測試類

public class Test {
    public static void main(String[] args) {
        User u1 = new User("遊客","2");
    //  User u1 = new User("管理員","2");
        //創建被代理對象target
        UserService target = new UserServiceIpm(u1);
        //獲取被代理對象類類型
        Class<? extends UserService> c = target.getClass();
        //獲取被代理對象的類加載器
        ClassLoader classLoader = c.getClassLoader();
        //獲取被代理對象實現的接口
        Class<?>[] interfaces = c.getInterfaces();
        //創建代理類對象h,傳被代理類對象target過去
        InvocationHandler h = new UserServiceProxy(target);
        //被代理類創建代理
        UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, h);
        User user = new User("會員","1");
        target.showUsersInfo(user);
        System.out.println("--------");
        proxy.showUsersInfo(user);
    }
}

兩者的區別

  • 靜態代理
    • 代理單一目標對象
    • 在代理類實現時就指定與被代理類相同的接口(運行前)
    • 優點
      • 降低了系統的耦合度
      • 代理對象作爲客戶端和目標對象之間的中介,起到了保護目標對象的作用
    • 缺點
      • 增加了代理對象,因此會造成請求的處理速度變慢
      • 增加了系統實現的複雜度
  • 動態代理
    • 代理多個目標對象
    • 不需要顯式實現與被代理類相同的接口,而是將這種實現推遲到程序運行時由JVM來實現。(運行時)
    • 優點
      • 只需要1個動態代理類就可以解決創建多個靜態代理的問題
      • 靈活性強,在使用時(調用被代理類對象)纔會動態創建動態代理類實例,不需要事先實例化
    • 缺點
      • 效率低,需要先通過Java反射機制,間接調用目標對象方法。
      • 只能針對接口創建代理類,不能針對類創建代理類,即只能動態代理 實現了接口的類。
    • 具體應用場景:面向切面編程(AOP),日誌記錄、性能統計、安全控制、異常處理等
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章