1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CompositeパターンとDI

Posted at

やりたかったこと

  • 最新トレンド情報の取得元を拡張しやすいようにしたい
  • 択一/集約の選択も自由にできるようになりたい

⇒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")));
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?