當和朋友談到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應用層面的實現,有兩種常見的方式。
-
靜態代理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面向切麵編程思想的內容了,希望我講解的內容能夠幫到大家。哈,希望伙伴們給個小心心!