2012-10-16 42 views

回答

0

嘗試這樣的方式,可以很容易地添加這個橫切關注點設計應用程序。例如,把業務邏輯/行爲用於單次使用的情況下在一類,並用一個通用的接口裝飾它:

public interface IUseCaseHandler<TUseCase> 
{ 
    void Handle(TUseCase useCase); 
} 

用例的定義是一個簡單的DTO(數據傳輸對象):

public class MoveCustomerUseCase 
{ 
    public int CustomerId { get; set; } 

    public Address Address { get; set; } 
} 

實現可以是這樣的:

public class MoveCustomerUseCaseHandler 
    : IUseCaseHandler<MoveCustomerUseCase> 
{ 
    public void Handle(MoveCustomerUseCase useCase) 
    { 
     // todo: business logic 
    } 
} 

你是怎麼獲得嗎?那麼,當全部使用辦案實現IUseCaseHandler<T>界面,你可以寫一個decorator所有的處理程序:

public class DurationMeasuringUseCaseHandlerDecorator<TUseCase> 
    : IUseCaseHandler<TUseCase> 
{ 
    private readonly IUseCaseHandler<TUseCase> decoratedInstance; 
    private readonly ILogger logger; 

    public DurationMeasuringUseCaseHandlerDecorator(
     IUseCaseHandler<TUseCase> decoratedInstance, 
     ILogger logger) 
    { 
     this.decoratedInstance = decoratedInstance; 
     this.logger = logger; 
    } 

    public void Handle(TUseCase useCase) 
    { 
     var stopwatch = System.Diagnostics.Stopwatch.StartNew(); 

     try 
     { 
      // call the real use case handler 
      this.decoratedInstance.Handle(useCase); 
     } 
     finally 
     { 
      this.logger.Log(typeof(TUseCase).Name + 
       " executed in " + 
       stopwatch.ElapsedMiliseconds + " ms."); 
     } 
    } 
} 

這似乎是一個很大的代碼記錄的一點點,不是嗎?實際上,並非如此。這是您唯一需要編寫代碼的時間,並且您不必更改任何用例處理程序來添加度量。你可以只包住這樣所有的處理程序:

// Composing the object graph 
IUseCaseHandler<MoveCustomerUseCase> handler = 
    newMoveCustomerUseCaseHandler(
     new MoveCustomerUseCaseHandler(), 
     new Logger()); 

// Using the object (somewhere else in the code) 
handler.Handle(new MoveCustomerUseCase { CustomerId = id, Address = adr }); 

但現在我們仍然必須我們想用這種每次連接到一起的對象圖?這是IoC容器進入圖片的地方。例如,使用Simple Injector,它需要一行代碼在系統中註冊的所有的用例的處理程序:

​​

通過所有公共類型的組件中的RegisterManyForOpenGeneric方法迭代,並登記該實施IUseCaseHandler<T>接口的所有具體類型,通過其封閉的通用表示(如IUseCaseHandler<MoveCustomerUseCase>)。

包裝紙的所有處理與裝飾只是另一種的一行:

container.RegisterDecorator(typeof(IUseCaseHandler<>), 
    typeof(DurationMeasuringUseCaseHandlerDecorator<>)); 

有了這個配置,我們可以要求containerIUseCaseHandler<MoveCustomerUseCase>,它將返回作爲MoveCustomerUseCaseHandler包裹着DurationMeasuringUseCaseHandlerDecorator<MoveCustomerUseCase>

var handler = 
    container.GetInstance<IUseCaseHandler<MoveCustomerUseCase>>(); 

handler.Handle(new MoveCustomerUseCase 
{ 
    CustomerId = id, Address = adr 
}); 
0

您可以使用C#的AOP庫,如postsharp。從postsharp文檔

修改例如:

/// <summary> 
/// Aspect that, when applied on a method, emits a trace message before and 
/// after the method execution. 
/// </summary> 
[Serializable] 
public class TraceAttribute : OnMethodBoundaryAspect 
{ 
    private string methodName; 
    private DateTime startTime; 

    /// <summary> 
    /// Method executed at build time. Initializes the aspect instance. After the execution 
    /// of <see cref="CompileTimeInitialize"/>, the aspect is serialized as a managed 
    /// resource inside the transformed assembly, and deserialized at runtime. 
    /// </summary> 
    /// <param name="method">Method to which the current aspect instance 
    /// has been applied.</param> 
    /// <param name="aspectInfo">Unused.</param> 
    public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo) 
    { 
     this.methodName = method.DeclaringType.FullName + "." + method.Name; 
    } 

    /// <summary> 
    /// Method invoked before the execution of the method to which the current 
    /// aspect is applied. 
    /// </summary> 
    /// <param name="args">Unused.</param> 
    public override void OnEntry(MethodExecutionArgs args) 
    { 
     startTime = DateTime.Now; 
     Trace.TraceInformation("{0}: Enter", this.methodName); 
     Trace.Indent(); 
    } 

    /// <summary> 
    /// Method invoked after successfull execution of the method to which the current 
    /// aspect is applied. 
    /// </summary> 
    /// <param name="args">Unused.</param> 
    public override void OnSuccess(MethodExecutionArgs args) 
    { 
     Trace.Unindent(); 
     var duration = DateTime.Now - startTime; 
     Trace.TraceInformation("{0}: Success, Duration: {1}ms", this.methodName, duration.TotalMilliseconds); 
    } 
} 

要在項目中應用此每個方法,你只需要編輯的程序集信息。cs並添加:

[assembly: SomeNamespace.TraceAttribute()] 

這是積極的一面,它是完全無創的,不需要對現有代碼進行更改。

+0

不要使用代碼編織,使用良好的設計;-) – Steven

+0

如果你有一個可怕的遺留應用程序,你在設計中沒有任何說法 - AOP可以是非常有用的。 – Vedran

相關問題