當我會AOP之後,去丈母娘家都是挺著胸脯!

来源:https://www.cnblogs.com/ISangyu/archive/2022/05/16/16278559.html
-Advertisement-
Play Games

當和朋友談到AOP時,第一映像會說AOP的應用層面,比如攔截器、過濾器,實現復用等等使用層面上。 這些應用層面上的回答遠遠沒有深入AOP的思想。是的,AOP是思想,面向切麵思想。 既然是編程思想,那我們就有必要瞭解AOP的整個過程,以及AOP思想出現的原因。 AOP面向切麵編程思想,能夠解決什麼問題 ...


 

圖片

 

當和朋友談到AOP時,第一映像會說AOP的應用層面,比如攔截器、過濾器,實現復用等等使用層面上。

 

這些應用層面上的回答遠遠沒有深入AOP的思想。是的,AOP是思想,面向切麵思想。

 

既然是編程思想,那我們就有必要瞭解AOP的整個過程,以及AOP思想出現的原因。

圖片

 

AOP面向切麵編程思想,能夠解決什麼問題,我們回顧一下編程思想的發展路線......

 

早期的POP面向過程編程即是以功能為中心來進行思考和組織的一種編程方法,強調的是功能

 

分析解決問題所需要的步驟,然後用函數把這些步驟一一實現,使用的時按順序依次調用,嚴格按照順序,側重解決步驟,著眼局部或具體。

 

實際是一種單一的思考方式,符合人類的思考方式,是一種基礎的方法,從實際出發。

 

它能夠流程化編程任務,只需要考慮實現方式和最終結果;開發效率高,代碼短小精悍,善於結合數據結構來開發高效率的程式;明確流程,步驟清楚,便於節點分析。

 

但是,需要深入思考,比較耗費精力;代碼復用性低,不易擴展,維護難度大,且面向過程的模塊化難度較高,耦合度也高。

 

由此可見,隨著時代發展,面對的系統逐漸複雜,一般的POP無法滿足,於是出現了OOP面向對象編程思想。

 

需要說明的是,並不是因為OOP的出現,才使得POP沒有餘地,或許有不少的伙伴甚至沒聽過POP。POP和OOP其實是一種互補關係,相關複雜問題拆解之後還是會回歸到面向過程的思想。

 

OOP,面向對象編程,以對象為中心,複雜系統出現時,盛行的一種新型的程式設計思想。以對象模型為基礎進行的抽象過程,併在應用過程中描述自己的抽象概念定義,包括對象、類、封裝、繼承等語法和概念。

 

通常脫口而出“萬物皆對象”,它可以搭建大型的複雜的系統,它是將數據抽象為模塊結構,然後必須存在某種方式來實現代碼的多態執行,最後它能壓縮部分代碼和函數。

 

或許不是很好理解。

 

舉個例子,比如說:我們的系統是一個建築,那類/對象就是磚塊,磚塊能夠組成牆,牆能構成房間,房間組合在一起就組成了一棟建築。

 

圖片

 

這是不是和我們面向對象編程時是一樣的?一個模塊由多個類共同實現,模塊又組成了某項服務,多個服務構成了一個完整的系統。

 

那麼,POP能夠滿足精簡系統的開發,OOP能夠滿足複雜的系統,為什麼還會出現AOP呢?

 

首先,構建了一個系統之後,依然會有需求的存在,有了需求就會難免調整代碼,那麼類就會發生變化,如果大規模變化將是不現實的,整個系統就會存在隱患以及人力物力的多餘需求。

 

類應該是固定的,不應該頻繁更改,之所以出現了那麼多的設計原則和設計模式,目的就是針對不斷的需求變化而進行拆解分離,使我們的類能夠像磚塊一樣固定,從而讓系統穩健。

 

我們設計完一個系統之後,新增需求要增加一個日誌列印模塊,授權模塊,如果在各個模塊都添加的話改動的工作量無疑是很大的,存在的隱患也是很大的。

 

從對象的組織角度來講,類是繼承關係,適合縱向擴展,這也是OOP的思想。

 

就像我們的建築,打好地基穩固之後,縱向增加樓層是相對較方便的,但是橫向擴展是很困難的。

 

因此,面向對象設計有兩個缺陷:

 

1.共性問題,面向對象設計一般是縱向思維,總會有一些共性不足。

 

2.擴展問題,當我們需要對現有的對象動態的新增某些行為或責任時就會變得比較困難。

 

於是,AOP出現了,來彌補OOP的共性問題和擴展問題。

 

當然,AOP不是OOP的升級版,是對OOP缺陷的補充

 

POP,OOP,AOP 這三種編程方式,本質也是互相彌補,從來不是哪個盛行而其他的就需要了。

那麼到底什麼是AOP呢?

 

AOP面向切麵編程,切麵就是橫切關註點模塊化,OOP是使用類狀態(屬性)和行為模塊化。

 

類和介面組織的,是針對橫向關註點,跨越應用程式的多個模塊的功能需求。

 

AOP涉及的應用,例如:日誌記錄、性能統計、安全控制,異常處理。都是可以從業務代碼中劃分出來,非業務邏輯的方法。

 

AOP善於將公共的功能提取出來,成立公共的模塊,只關註通用的功能,不關註業務邏輯。

 

AOP的優勢:

 

1.將通用的功能從業務邏輯中抽離出來,提高代碼的復用性,有利於後期的維護和擴展。

 

2.在軟體設計時,抽出通用功能,有利於軟體設計的模塊化,降低架構的複雜度。

 

AOP與 OOP所針對的目標是不同的。OOP針對業務處理過程的實體、屬性,行為進行抽象封裝。

 

AOP則是針對業務處理過程中切麵進行提取,就是面向對象過程中的某個步驟或階段的提取,來降低邏輯過程中各個部分的耦合。

 

因此,相比於OOP,可以總結出AOP的特點。

 

1.面向目標不同,OOP面向名詞,AOP面向動詞。

 

2.思想結構不同,OOP是縱向,AOP是橫向。

 

3.註重方面不同,OOP偏重業務邏輯單元劃分,AOP偏重業務處理過程中的某個步驟。


那麼,我們在AOP應用層面的實現,有兩種常見的方式。

 

  1. 靜態代理AOP,就是手寫代碼。

 

我們以裝飾器模式為例子,裝飾器就是在一個原有對象的情況下封裝一個新的裝飾器類,來包裝原有類,提供額外的功能。

 

//介面服務
public interface ITravelService
{
  Task PlanToTravel(Travel travel);
}
public class TravelService : ITravelService
{
   public Task PlanToTravel(Travel travel)
   {
      Console.WriteLine($"旅客{travel.name}成功加入旅行團");
      return Task.CompletedTask;
    }
}

 

//裝飾器
public class TravelDecorator : ITravelService
{
  private readonly ITravelService _travelService;

  public TravelDecorator(ITravelService travelService)
  {
    _travelService = travelService;
  }

  public async Task PlanToTravel(Travel travel)
  {
    //旅行前
    await IsAllowToTravel(travel);
    await _travelService.PlanToTravel(travel);
    //旅行後
    await IsAllowBack(travel);
  }
  public Task IsAllowToTravel(Travel travel)
  {
    Console.WriteLine($"目前處於疫情嚴重,將停止旅游!");
    return Task.CompletedTask;
  }
  public Task IsAllowBack(Travel travel)
  {
    Console.WriteLine($"返回目標地處於風控期,暫時無法返航!");
    return Task.CompletedTask;
  }

 

2.動態代理實現,可以通過反射來實現。

 

例如現有的AOP框架,Romoting(分散式通訊框架)、Castle輕量級容器(包含實現ORM、IOC、MVC,AOP)、Unity(IOC容器,AOP)。

 

以 Remoting和Castle 分別寫一個實例,如下:

 

//Remoting 例子
public class DynamicProxy<T> : DispatchProxy where T : class
{
  public T Target { get; set; }
  public DynamicProxy(){}
  //執行之前執行邏輯
  public Action BeforAction { get; set; }
  //執行之後執行邏輯
  public Action AfterAction { get; set; }

  public static T Decorate(T target, Action BeforAction, Action AfterAction)
  {
    // DispatchProxy.Create creates proxy objects
    var proxy = Create<T, DynamicProxy<T>>() as DynamicProxy<T>;
    proxy.AfterAction = AfterAction;
    proxy.BeforAction = BeforAction;

    // If the proxy wraps an underlying object, it must be supplied after creating the proxy.
    proxy.Target = target ?? Activator.CreateInstance<T>();
    return proxy as T;
  }
  protected override object Invoke(MethodInfo targetMethod, object[] args)
  {
    //執行業務之前的代碼邏輯
    BeforAction();
    var result = targetMethod.Invoke(Target, args);
    //執行業務之後的代碼邏輯
    AfterAction();
    return result;
        }
    }
//remoting 實例 使用方式
var tralvel = new Travel
    {
       name = "張三",
       date = DateTime.Now,
       telphone = "110",
       travel_target = "HangZhou"
     };
     
var service = new TravelService();
var proxyService = DynamicProxy<ITravelService>.Decorate(service,
          () => { Console.WriteLine("執行邏輯前"); },
          () => { Console.WriteLine("執行邏輯後"); });

proxyService.PlanToTravel(tralvel);

 

//castle 實例 
public class CastleProxy<T> : IInterceptor where T : class
{
  private static readonly ProxyGenerator _generator = new ProxyGenerator();
  public T Target { get; set; }
  public CastleProxy(){}
  //執行之前
  public Action BeforAction { get; set; }
  //執行之後
  public Action AfterAction { get; set; }
  public static T Decorate(T target, Action BeforActions, Action AfterActions)
  {
    var proxy = target != null ?
        _generator.CreateInterfaceProxyWithTarget(target, new CastleProxy<T>() 
          {
             BeforAction = BeforActions,
             AfterAction = AfterActions 
           }):
         _generator.CreateInterfaceProxyWithTarget<T>(Activator.CreateInstance(typeof(T)) as T,new CastleProxy<T>()
          {
             BeforAction = BeforActions,
             AfterAction = AfterActions
          });
    
    return proxy;
  }
  public void Intercept(IInvocation invocation)
  {
    try
       {
        BeforAction();
        invocation.Proceed();//程式執行
        AfterAction();
       }
       catch (TargetInvocationException error)
       {
        throw error.InnerException;
       }
  }
}
//castle 實例 使用方式
var tralvel = new Travel
    {
       name = "張三",
       date = DateTime.Now,
       telphone = "110",
       travel_target = "HangZhou"
     };
     
var service = new TravelService();
var proxyService = CastleProxy<ITravelService>.Decorate(service,
          () => { Console.WriteLine("執行邏輯前"); },
          () => { Console.WriteLine("執行邏輯後"); });

proxyService.PlanToTravel(tralvel);

 

好了,以上就是AOP面向切麵編程思想的內容了,希望我講解的內容能夠幫到大家。哈,希望伙伴們給個小心心!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 5月17日,2022年搜狐科技峰會成功舉辦,峰會匯聚各界大咖,共同探討AI 技術的深入應用以及行業數字化的發展趨勢。華為終端雲服務應用生態BU總裁望岳發表題為《使能AI智慧體驗,共建創新應用生態》主題演講。 望岳表示,經過多年的發展迭代,華為移動服務HMS生態已成為全球第三大移動應用生態:截止今天, ...
  • 5月18日(周三)晚上19:00,第一期戰“碼”先鋒直播,我們邀請到了潤和資深軟體開發工程師趙海鵬老師,在直播間與大家分享《如何成為一名優秀的OpenHamrony 貢獻者?》 ...
  • HUAWEI Developer Day(簡稱HDD),是華為開發者聯盟與廣大開發者深度交流的平臺。圍繞移動終端的最新技術和產品形態,持續向廣大開發者傳遞華為終端的最新產品和開放服務能力,結合最新的行業發展趨勢,攜手開發者共同打造面向終端消費者的卓越用戶體驗。 5月24日18:50-21:05,HD ...
  • 本文對 CSS 中有關大小的四種自適應大小表現進行瞭解釋與區別,它們分別是 fit-content, min-content, max-content, fill-available。相對而言,本文較為嚴謹,即儘量地無遺漏、無歧義。在嚴謹的同時,也做到儘可能通俗易懂。 ...
  • BOM BOM:Broswer object model,即瀏覽器提供我們開發者在javascript用於操作瀏覽器的對象。 BOM就是瀏覽器對象模型 BOM提供了一些獨立於內容頁面與瀏覽器視窗進行交互的對象介面 BOM的核心是window對象,所以window一般在書寫時是可以省略的. BOM其實 ...
  • 完整項目地址: [email protected]:xsk-walter/myPromise.git // index.js /* 1. Promise 就是一個類 在執行這個類的時候 需要傳遞一個執行器進去 執行器會立即執行 2. Promise 中有三種狀態 分別為 成功 fulfilled 失敗 r ...
  • 前端周刊:2022-7 期 前端開發 videojs-plugin-source-switcher videojs 視頻源切換插件 前端工具箱-免費的 SVG 圖像和圖標 所有內容均在 Creative Commons CC0 下發佈 es6-模塊與-commonjs-模塊的差異 CommonJS ...
  • 本章是系列文章的第三章,介紹了基於數據流分析的一些優化方法。包括生命周期管理,可獲得表達式,常用表達式,可達性定義。本章在介紹這4中分析方法的基礎上提取出它們的通用模式。這一章形式化的內容比較多,看的時候有點燒腦,最好自己手工推導一下,要不然基本上看不懂:) 本文中的所有內容來自學習DCC888的學 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...