直接向需要它的消費者注入數據可能在某些情況下有效,但在大多數情況下,消費者通過查詢此數據(使用提供的參數詢問數據)確定他需要哪些數據。
對於那些可以直接注入數據的情況(您可以將它們視爲無參數查詢),直接注入數據會使您的DI配置非常複雜。以一個依賴於系統當前時間的消費者爲例。您可以將DateTime
注入消費者(或甚至是Lazy<DateTime>
)。另一位消費者可能需要當前用戶的出生日期,因此此消費者也取決於DateTime
。但是現在你在系統中不明確,因爲DateTime
依賴有兩個含義。 DI容器在處理這個問題上不好,爲了解決這個問題,你必須明確地告訴容器什麼DateTime
對於每個需要它的消費者意味着什麼。這導致難以容納的脆性結構。
對於後一種情況(無參數查詢),解決方案是定義可以解析的無歧義接口。在上面的示例中,您可以定義一個ITimeProvider
接口和一個IUserContext
接口。每個消費者可以依賴正確的界面。
對於前一種情況(參數化查詢),您不需要這樣的框架;你需要適當的設計。
您正在討論查詢數據庫和Web服務,並需要緩存返回的數據的方法。因此,您需要的是定義查詢的抽象,並且可以以可插入的方式將緩存和其他cross-cutting concerns應用於其中,並且無需對代碼進行任何更改。
做到這一點的一個有效方法是通過定義限定查詢對象(查詢的輸入參數)+返回類型,和一個接口,定義用於處理該查詢的邏輯接口:
public interface IQuery<TResult>
{
}
public interface IQueryHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
有了這些抽象可以定義一個查詢對象是這樣的:
public class FindUsersBySearchTextQuery : IQuery<User[]>
{
public string SearchText { get; set; }
public bool IncludeInactiveUsers { get; set; }
}
此對象定義由搜索文本查找用戶,並允許包含或不活動的用戶的排斥的查詢,並且查詢結果是陣列User
個物體。
,執行該查詢可以實現如下的邏輯:
public class FindUsersBySearchTextQueryHandler
: IQueryHandler<FindUsersBySearchTextQuery, User[]>
{
private readonly NorthwindUnitOfWork db;
public FindUsersBySearchTextQueryHandler(
NorthwindUnitOfWork db)
{
this.db = db;
}
public User[] Handle(FindUsersBySearchTextQuery query)
{
return (
from user in this.db.Users
where user.Name.Contains(query.SearchText)
where user.IsActive || query.IncludeInactiveUsers
select user)
.ToArray();
}
}
爲什麼究竟該解決你有問題嗎?這解決了您的問題,因爲消費者可以依賴IQueryHandler<FindUsersBySearchTextQuery, User[]>
界面,而您可以用decorators包裝IQueryHandler<T>
實施,而無需任何人知道。編寫緩存導致胎面局部stogage一個裝飾是一個沒有腦子:
public class TlsCachingQueryHandlerDecorator<TQuery, TResult>
: IQueryHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
where TResult : class
{
[ThreadStatic]
private static TResult cache;
private readonly IQueryHandler<TQuery, TResult> decorated;
public ValidationQueryHandlerDecorator(
IQueryHandler<TQuery, TResult> decorated)
{
this.decorated = decorated;
}
public TResult Handle(TQuery query)
{
return cache ?? (cache = this.decorated.Handle(query));
}
}
任何固體DI容器,您可以註冊這些裝飾,讓你註冊的裝飾有條件的(基於類型的信息裝飾類型)。這使您可以將此緩存修飾器僅放置在可以安全緩存的類型上(根據您的條件)。
您可以在這篇文章中找到關於此模型的更多信息:Meanwhile… on the query side of my architecture。