<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      Fork me on GitHub

      設計模式:代理模式詳解

      需求場景

      按著慣例,還是以一個應用場景作為代理模式的切入點。現在有一個訂單系統,要求是:一旦訂單被創建,只有訂單的創建人才可以修改訂單中的數據,其他人則不能修改。

      基本實現思路

      按著最直白的思路,就是查詢數據庫中訂單的創建人和當前Session中的登錄賬號ID是否一致。

      class Order {
          private String orderId;
          private String creatorId; // 訂單創建者的ID
          private String details; // 訂單詳情
          // 省略其他屬性和getter/setter方法
       
          public Order(String orderId, String creatorId, String details) {
              this.orderId = orderId;
              this.creatorId = creatorId;
              this.details = details;
          }
       
          // 其他業務邏輯...
      }

      系統修改

      class OrderService {
          private Map<String, Order> orders = new HashMap<>();
       
          // 創建訂單
          public void createOrder(String orderId, String creatorId, String details) {
              Order order = new Order(orderId, creatorId, details);
              orders.put(orderId, order);
          }
       
          // 修改訂單
          public void modifyOrder(String orderId, String userId, String newDetails) {
              Order order = orders.get(orderId);
              if (order != null) {
                  //檢查是否擁有權限
                  if(order.getCreateId().equals(userId)){
                      order.setDetails(newDetails);
                  }else{
                     System.out.println("權限不足.");
                  }
              } else {
                  System.out.println("訂單不存在.");
              }
          }
       
          // 其他業務邏輯...
      }

      該思路的問題

      上述代碼其實本身是沒有問題的,也是Web貧血模式的常見實現思路,即在Service中通過大量的if else進行完成,如果非說問題的話,就是隨著對于訂單的操作越多Service代碼會越發膨脹,例如,需求一開始是只要求改描述,下次又要求更改名稱,下下次對于權限又細分等等,Service的modifyOrder就會增加很多的if else和set方法 ,擴展和維護十分的不優雅。或許下面的代理模式能提供一些能夠優雅解決的新思路。

      代理模式

      代理模式的核心定義是:為其他對象提供一種代理以此來控制對這個對象的訪問。代理模式是以對象組合的方式對對象進行保護或者說功能擴展的一種方式。

      代理模式結構

      Sunject :目標接口,定義目標對象的具體操作。

      Proxy:代理對象,實現與具體的目標對象一樣的接口,這樣就可以代理具體的目標對象。保存一個指向具體目標對象的引用,可以再需要的時候調用具體的目標對象,調用目標對象時進行控制和保護。

      RealSubject:具體的目標對象,真正實現目標接口要求的功能

      // 定義真實主題角色接口
      interface Image {
          void display();
      }
       
      // 實現真實主題角色
      class RealImage implements Image {
          private String fileName;
       
          public RealImage(String fileName) {
              this.fileName = fileName;
              loadFromDisk(fileName);
          }
       
          @Override
          public void display() {
              System.out.println("Displaying " + fileName);
          }
       
          // 模擬從磁盤加載圖片資源
          private void loadFromDisk(String fileName) {
              System.out.println("Loading " + fileName + " from disk.");
          }
      }
       
      // 定義代理主題角色
      interface Proxy extends Image {
          void display();
      }
       
      // 實現代理主題角色
      class ProxyImage implements Proxy {
          private RealImage realImage;
       
          public ProxyImage(String fileName) {
              // 延遲加載RealImage對象
              this.realImage = null;
          }
       
          @Override
          public void display() {
              if (realImage == null) {
                  realImage = new RealImage("image.png");
              }
              realImage.display();
          }
      }
       
      public class ProxyPatternDemo {
          public static void main(String[] args) {
              Proxy proxy = new ProxyImage("image.png");
              proxy.display();
          }
      }

      代理模式實現案例

      相當于現在如果有了一個訂單對象實例,那么就需要控制外部對它的訪問,滿足條件的可以訪問,不滿足條件的就不能訪問。使用代理模式來實現就是需要在Order對象之外再包一層對象,用于操作權限控制。本質上是一種保護代理思路。

      首先創建一個訂單的操作接口

      public interface OrderApi {
          String getId();
          String getName();
          String getDetails();
          String getCreatorId();
          void setId(String id);
          void setDetails(String details);
          void setName(String name);
          void setCreatorId(String creatorId);
      }

       一個基本的訂單實體類作為目標代理對象

      class Order implements OrderApi {
          private String id;
          private String name;
          private String details;
          private String creatorId;
       
          public Order(String id, String name, String details, String creatorId) {
              this.id = id;
              this.name = name;
              this.details = details;
              this.creatorId = creatorId;
          }
       
          @Override
          public String getId() {
              return id;
          }
       
          @Override
          public String getName() {
              return name;
          }
       
          @Override
          public String getDetails() {
              return details;
          }
       
          @Override
          public String getCreatorId() {
              return creatorId;
          }
       
          @Override
          public void setId(String id) {
             
              this.id = id;
          }
       
          @Override
          public void setName(String name) {
              
              this.name = name;
          }
       
          @Override
          public void setCreatorId(String creatorId) {
              this.creatorId = creatorId;
          }
          
          @Override
          public void setDetails(String details) {
              this.details= details;
          }
      }

      實現一個代理對象

      class OrderProxy implements OrderApi {
          private Order order;
       
          public OrderProxy(Order order) {
              this.order = order;
          }
       
          @Override
          public String getId() {
              return order.getIdO();
          }
       
          @Override
          public String getName() {
              return order.getNameO();
          }
       
          @Override
          public String getDetails() {
              return order.getDetailsO();
          }
       
          @Override
          public String getCreatorId() {
              return order.getCreatorIdO();
          }
       
          @Override
          public void setId(String id) {
              // 在這里添加權限檢查邏輯
              if (isCreator()) {
                  order.setId(id);
              } else {
                  throw new SecurityException("Only the creator can change the order ID.");
              }
          }
       
          @Override
          public void setName(String name) {
              // 在這里添加權限檢查邏輯
              if (isCreator()) {
                  order.setName(name);
              } else {
                  throw new SecurityException("Only the creator can change the order name.");
              }
          }
       
          @Override
          public void setCreatorId(String creatorId) {
              // 創建者ID通常不允許更改
              throw new UnsupportedOperationException("Changing creator ID is not allowed.");
          }
       
          private boolean isCreator(String userId) {
              // 這里應該添加檢查userId是否是訂單的創建者
              // 為了示例簡單,這里假設userId總是傳入正確的,返回true
              return true;
          }
      }

      代理模式的理解

      特點與分類

      代理模式在客戶和被客戶訪問的對象之間,引入了一定程度的間接性,客戶是直接使用代理,讓代理來與被訪問的對象進行交互。不同的代理類型,這種附加的間接性有不同的用途,也就具有不同的特點。

      • 遠程代理:隱藏了一個對象存在于不同的地址空間的事實,也即是客戶通過遠程代理去訪問一個對象,根本就不關心這個對象在哪里,也不關心如何通過網絡去訪問到這個對象。從客戶的角度來講,它只是在使用代理對象而已。
      • 虛代理:可以根據需要來創建“大”對象,只有到必須創建對象的時候,虛代理才會創建對象,從而大大加快程序運行速度,并節省資源。通過虛代理可以對系統進行優化。
      • 保護代理:可以在訪問一個對象的前后,執行很多附加的操作,除了進行權限控制之外,還可以進行很多跟業務相關的處理,而不需要修改被代理的對象。也就是說,可以通過代理來給目標對象增加功能。
      • 智能指引:和保護代理類似,也是允許在訪問一個對象的前后,執行很多附加的操作,這樣一來就可以做很多額外的事情,比如,引用計數等。

      在這些代理類型中,最常見的是保護代理和遠程代理。上述的例子就是一個典型的保護代理的實現,即具體訂單的操作是不變的,如果需要對訂單的操作進行特殊處理,一切變動皆集中在代理對象中,代理對象對于訂單對象起到了保護隔離的作用,同時代碼層面上也承載了“頻繁變化”的需求內容,將“變化”隔離出來,對于后續的需求擴展也是十分有效。

      建議在如下情況中選用代理模式。

      • 需要為一個對象在不同的地址空間提供局部代表的時候,可以使用遠程代理。
      • 需要按照需要創建開銷很大的對象的時候,可以使用虛代理。
      • 需要控制對原始對象的訪問的時候,可以使用保護代理。
      • 需要在訪問對象執行一些附加操作的時候,可以使用智能指引代理。

      具體目標和代理間的關系

      Java中代理模式的應用

      Java 對代理模式提供了內建的支持,在java.lang,refect 包下面,提供了一個 Proxy的類和一個InvocationHandler 的接口。
      通常把前面自己實現的代理模式稱為 Java 的靜態代理。這種實現方式有一個較大的缺點,就是如果Subject接口發生變化,那么代理類和具體的目標實現都要變化,不是很靈活。而使用Java內建的對代理模式支持的功能來實現則沒有這個問題。
      通常把使用 Java 內建的對代理模式支持的功能來實現的代理稱為Java的動態代理,動態代理跟靜態代理相比,明顯的變化是:靜態代理實現的時候,在Subject接口上定義很多的方法,代理類里面自然也要實現很多方法:而動態代理實現的時候,雖然Subicct接口上定義了很多方法,但是動態代理類始終只有一個invoke 方法。這樣,當Subject接口發生變化的時候,動態代理的接口就不需要跟著變化了。
      Java的動態代理目前只能代理接口,基本的實現是依靠Java的反射機制和動態生成class的技術,來動態生成被代理的接口的實現對象。具體的內部實現細節這里不去討論。如果要實現類的代理,可以使用cglib(一個開源的Code Generation Library)。

      還是來看看示例,那就修改上面保護代理的示例,看看如何使用Java的動態代理來實現同樣的功能。
      (1)訂單接口的定義是完全一樣的,就不再贅述了。
      (2)訂單對象的實現,只是添加了一個 toString,,以方便測試輸出,這里也不去示例了。在前面的示例中,toString已實現在代理類里面了。
      (3)直接看看代理類的實現,大致有如下變化。

      • 要實現InvocationHandler接口。
      • 需要提供一個方法來實現:把具體的目標對象和動態代理綁定起來,并在綁定好過后,返回被代理的目標對象的接口,以利于客戶端的操作。
      • 需要實現 invoke 方法,在這個方法里面,具體判斷當前是在調用什么方法,需要如何處理
      import java.lang.reflect.*;
       
      /**
       * 使用Java中的動態代理
       */
      public class DynamicProxy implements InvocationHandler {
          // 被代理的對象
          private OrderApi order;
       
          /**
           * 獲取綁定好代理和具體目標對象后的目標對象的接口
           * @param order 具體的訂單對象,相當于具體目標對象
           * @return 綁定好代理和具體目標對象后的目標對象的接口
           */
          public OrderApi getProxyInterface(Order order) {
              // 設置被代理的對象,方便invoke里面的操作
              this.order = order;
       
              // 把真正的訂單對象和動態代理關聯起來
              OrderApi orderApi = (OrderApi) Proxy.newProxyInstance(
                  order.getClass().getClassLoader(),
                  order.getClass().getInterfaces(),
                  this);
       
              return orderApi;
          }
       
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              // 如果是調用setter方法就需要檢查權限
              if (method.getName().startsWith("set")) {
                  // 假設Order類有一個getOrderUser()方法來獲取訂單創建者的用戶ID
                  // 并且order.getOrderUser().equals(args[0])來檢查是否是創建者
                  if (order.getOrderUser() != null && order.getOrderUser().equals(args[0])) {
                      // 可以操作
                      return method.invoke(order, args);
                  } else {
                      // 如果不是創建者,不能修改
                      System.out.println("對不起," + args[0] + ",您無權修改本訂單中的數據");
                  }
              } else {
                  // 不是調用的setter方法就繼續運行
                  return method.invoke(order, args);
              }
              return null;
          }
      }

      使用規則

      public class Client {
          public static void main(String[] args) {
              // 張三先登錄系統創建了一個訂單
              Order order = new Order("XXX", 100, "張三");
              // 創建一個動態代理
              DynamicProxy dynamicProxy = new DynamicProxy();
              // 然后把訂單和動態代理關聯起來
              OrderApi orderApi = dynamicProxy.getProxyInterface(order);
       
              // 以下就需要使用被代理過的接口來操作了
              // 李四想要來修改,那就會報錯
              orderApi.setOrderNum(123, "李四");
              // 輸出order
              System.out.println("李四修改后訂單記錄沒有變化:" + orderApi);
       
              // 張三修改就不會有問題
              orderApi.setOrderNum(123, "張三");
              // 再次輸出order
              System.out.println("張三修改后,訂單記錄:" + orderApi);
          }
      }

      代理在Java中的使用十分常見,例如Spring中的AOP,其本質就是代理模式

       

       
      posted @ 2024-07-16 10:39  糖拌西紅柿  閱讀(689)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 精品人妻伦一二二区久久| 综合色久七七综合尤物| 中文在线最新版天堂| 亚洲色大成网站WWW久久| 美日韩不卡一区二区三区| 久久av色欲av久久蜜桃网| 国产99在线 | 欧美| 国产一区二区三区精品久| 亚洲一区二区偷拍精品| 国产日韩综合av在线| 亚洲av色精品一区二区| 中文字幕乱码在线人视频| 国产真人无遮挡免费视频| 国产免费高清69式视频在线观看| 中文字幕日韩有码第一页| 天天澡日日澡狠狠欧美老妇 | 精品中文字幕人妻一二| 国产成人精品永久免费视频| 在线高清免费不卡全码| 武清区| 麻豆a级片| 三上悠亚久久精品| 毛片网站在线观看| 亚洲欧美日韩综合在线丁香| 色猫咪av在线网址| 亚洲国产精品日韩av专区| 广东少妇大战黑人34厘米视频| 国产破外女出血视频| 妓女妓女一区二区三区在线观看| 国产亚洲国产精品二区| 成人3D动漫一区二区三区| 亚洲av第二区国产精品| 成人中文在线| 中文字幕人妻无码一区二区三区| 在线观看国产成人av天堂| 欧美成人精品三级网站| 国产亚洲精品自在久久vr| 自拍偷拍一区二区三区四| 浓毛老太交欧美老妇热爱乱| 欧美三级中文字幕在线观看| 7878成人国产在线观看|