當我會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
  • 1. 說明 /* Performs operations on System.String instances that contain file or directory path information. These operations are performed in a cross-pla ...
  • 視頻地址:【WebApi+Vue3從0到1搭建《許可權管理系統》系列視頻:搭建JWT系統鑒權-嗶哩嗶哩】 https://b23.tv/R6cOcDO qq群:801913255 一、在appsettings.json中設置鑒權屬性 /*jwt鑒權*/ "JwtSetting": { "Issuer" ...
  • 引言 集成測試可在包含應用支持基礎結構(如資料庫、文件系統和網路)的級別上確保應用組件功能正常。 ASP.NET Core 通過將單元測試框架與測試 Web 主機和記憶體中測試伺服器結合使用來支持集成測試。 簡介 集成測試與單元測試相比,能夠在更廣泛的級別上評估應用的組件,確認多個組件一起工作以生成預 ...
  • 在.NET Emit編程中,我們探討了運算操作指令的重要性和應用。這些指令包括各種數學運算、位操作和比較操作,能夠在動態生成的代碼中實現對數據的處理和操作。通過這些指令,開發人員可以靈活地進行算術運算、邏輯運算和比較操作,從而實現各種複雜的演算法和邏輯......本篇之後,將進入第七部分:實戰項目 ...
  • 前言 多表頭表格是一個常見的業務需求,然而WPF中卻沒有預設實現這個功能,得益於WPF強大的控制項模板設計,我們可以通過修改控制項模板的方式自己實現它。 一、需求分析 下圖為一個典型的統計表格,統計1-12月的數據。 此時我們有一個需求,需要將月份按季度劃分,以便能夠直觀地看到季度統計數據,以下為該需求 ...
  • 如何將 ASP.NET Core MVC 項目的視圖分離到另一個項目 在當下這個年代 SPA 已是主流,人們早已忘記了 MVC 以及 Razor 的故事。但是在某些場景下 SSR 還是有意想不到效果。比如某些靜態頁面,比如追求首屏載入速度的時候。最近在項目中回歸傳統效果還是不錯。 有的時候我們希望將 ...
  • System.AggregateException: 發生一個或多個錯誤。 > Microsoft.WebTools.Shared.Exceptions.WebToolsException: 生成失敗。檢查輸出視窗瞭解更多詳細信息。 內部異常堆棧跟蹤的結尾 > (內部異常 #0) Microsoft ...
  • 引言 在上一章節我們實戰了在Asp.Net Core中的項目實戰,這一章節講解一下如何測試Asp.Net Core的中間件。 TestServer 還記得我們在集成測試中提供的TestServer嗎? TestServer 是由 Microsoft.AspNetCore.TestHost 包提供的。 ...
  • 在發現結果為真的WHEN子句時,CASE表達式的真假值判斷會終止,剩餘的WHEN子句會被忽略: CASE WHEN col_1 IN ('a', 'b') THEN '第一' WHEN col_1 IN ('a') THEN '第二' ELSE '其他' END 註意: 統一各分支返回的數據類型. ...
  • 在C#編程世界中,語法的精妙之處往往體現在那些看似微小卻極具影響力的符號與結構之中。其中,“_ =” 這一組合突然出現還真不知道什麼意思。本文將深入剖析“_ =” 的含義、工作原理及其在實際編程中的廣泛應用,揭示其作為C#語法奇兵的重要角色。 一、下劃線 _:神秘的棄元符號 下劃線 _ 在C#中並非 ...