やりたかったこと
- 最新トレンド情報の取得元を拡張しやすいようにしたい
- 択一/集約の選択も自由にできるようになりたい
⇒compositeパターンを選んでみた
//Trendドメインオブジェクト@ドメイン層
public class Trend
{
public Trend(DateTime from, string word, int rank)
{
From = from;
Word = word;
Rank = rank;
}
public DateTime From { get; set; }
//ドメインルール(最新の定義は翌日まで)
public DateTime To { get => From.AddDays(1); }
public string Word { get; set; }
public int Rank { get; set; }
}
//Trend情報提供インターフェース@ドメイン層(クリーンアーキテクチャ、依存性逆転を考えていた)
public interface ITrendProvider
{
public Task<Trend> GetTrendAsync(DateTime from, DateTime to);
}
ぶつかった壁
単純にインターフェースにDIすると集約ルートとLeafが混在してしまう
2通りの対処
.net8未満
DI都合IFの活用
//DI都合IF@インフラ層
public interface ITrendProviderLeaf:ITrendProvider{
}
//集約ルート@インフラ層
public class TrendProvider: ITrendProvider
{
private readonly IEnumerable<ITrendProviderLeaf> _providers;
public TrendProvider(IEnumerable<ITrendProviderLeaf> providers)
{
_providers = providers;
}
public Task<Trend> GetTrendAsync(DateTime from, DateTime to)
{
//処理略
//_providers.Select(e => e.GetTrendAsync(from, to))…などイメージ
}
}
//Leaf1@インフラ層
public class GoogleTrend : ITrendProviderLeaf
{
public Task<Trend> GetTrendAsync(DateTime from, DateTime to)
{
//処理略
}
}
//Leaf2@インフラ層
public class XTrend : ITrendProviderLeaf
{
public Task<Trend> GetTrendAsync(DateTime from, DateTime to)
{
//処理略
}
}
//DI@アプリケーション層(Program.cs)
builder.Services.AddScoped<ITrendProviderLeaf, GoogleTrend>();
builder.Services.AddScoped<ITrendProviderLeaf, XTrend>();
builder.Services.AddScoped<ITrendProvider, TrendProvider>();
.net8以後
キー付きDIの活用
//集約ルート@インフラ層
public class TrendProvider: ITrendProvider
{
private readonly IEnumerable<ITrendProvider> _providers;
public TrendProvider(IEnumerable<ITrendProvider> providers)
{
_providers = providers;
}
public Task<Trend> GetTrendAsync(DateTime from, DateTime to)
{
//処理略
//_providers.Select(e => e.GetTrendAsync(from, to))…などイメージ
}
}
//Leaf1@インフラ層
public class GoogleTrend : ITrendProvider
{
public Task<Trend> GetTrendAsync(DateTime from, DateTime to)
{
//処理略
}
}
//Leaf2@インフラ層
public class XTrend : ITrendProvider
{
public Task<Trend> GetTrendAsync(DateTime from, DateTime to)
{
//処理略
}
}
//DI@アプリケーション層(Program.cs)
builder.Services.AddKeyedScoped<ITrendProvider, GoogleTrend>("leaf");
builder.Services.AddKeyedScoped<ITrendProvider, XTrend>("leaf");
builder.Services.AddScoped<ITrendProvider>(sp => new TrendProvider(sp.GetKeyedServices<ITrendProvider>("leaf")));