債券系SEの苦悩

SIer所属 8年目SEの備忘

MENU

【IT】DDD/ドメイン駆動設計 C#でファーストコレクションクラス

趣旨

C#でファーストコレクションクラスを作成する際に、インスタンス変数に対象クラスのListを保持することが多かったが、もっとスマートな方法がないかと思い調査したので記録する。
oita.oika.me

要諦

  • ファーストコレクションクラスでCollectionを継承する
  • ファーストコレクションクラスをフィルターすることがあるが、その方法についてまとめる

何がいいか

  • 金融系SIでは約定データのListを操作することが多く、そのようなデータを扱う際にファーストコレクションを利用すると保守性向上に寄与すると感じる。
  • また、Collectionを継承することで、これがファーストコレクションに相当するという実装意図が明確になり、ほかの人が見てもわかるソースになる。

ソース

説明

  • usingは省略してます。
  • 以下はMyClassという個別のクラスをまとめたファーストコレクションクラスを生成します。
  • 生成後、index=1のデータのみフィルターします。その際、List型ではなく、ファーストコレクションクラス自身を返します。

クライアント側

class Program
{
  static void Main(string[] args)
  {
    var myCollction = new MyClassCollection();

    //△ List<MyClass>型:List操作になるため、MyClassCollectionを作成した意味が半減する
    //また外部からデータを操作するのは望ましくない
    var val1 = myCollction.Where(x => x.index == 1).ToList();
    //〇 MyClassCollection型:想定通り
    var val2 = myCollction.ToFliter();
  }
}

ファーストコレクションクラス

  internal class MyClassCollection : Collection<MyClass>
  {
    public MyClassCollection()
    {
      //1,2,3の値を保持するデータを生成
      var xxx = new MyClass(1);
      var xxx2 = new MyClass(1);
      var xxx3 = new MyClass(1);
      var xxx4 = new MyClass(1);
      var xxx5 = new MyClass(2);
      var xxx6 = new MyClass(3);
      base.Items.Add(xxx);
      base.Items.Add(xxx2);
      base.Items.Add(xxx3);
      base.Items.Add(xxx4);
      base.Items.Add(xxx5);
      base.Items.Add(xxx6);
    }

    //★こいつでフィルターした結果を生成可能
    private MyClassCollection(IList<MyClass> list) : base(list) { }

    public MyClassCollection ToFliter()
    {
      var list = base.Items.Where(x => x.index == 1).ToList();
      return new MyClassCollection(list);  //★引数付コンストラクタ
    }
  }

個別のクラス

internal class MyClass
{
  public int index { get; private set; }
  public MyClass(int i)
  {
    this.index = i;
  }
}

参考 Collectionの中身

namespace System.Collections.ObjectModel
{
  [DefaultMember("Item")]
  public class Collection<T> : ICollection<T>, IEnumerable<T>, IEnumerable, IList<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection, IList
  {
    public Collection();
    public Collection(IList<T> list);

    public T this[int index] { get; set; }

    public int Count { get; }
    protected IList<T> Items { get; }

    public void Add(T item);
    public void Clear();
    public bool Contains(T item);
    public void CopyTo(T[] array, int index);
    public IEnumerator<T> GetEnumerator();
    public int IndexOf(T item);
    public void Insert(int index, T item);
    public bool Remove(T item);
    public void RemoveAt(int index);
    protected virtual void ClearItems();
    protected virtual void InsertItem(int index, T item);
    protected virtual void RemoveItem(int index);
    protected virtual void SetItem(int index, T item);
  }
}