コンストラクタが膨らんだ時の対処法

はじめに

クラスのプロパティが多くなると、それに伴ってコンストラクタで渡すパラメータも増えてしまいます。これについての対処法を記載します。
サンプルコードはC#です。

1. 必須とオプションのプロパティを分ける

必須のみコンストラクタで受け取り、それ以外はオブジェクト初期化子で受け取ります。
ただし必須項目が多いとコンストラクタが膨れ上がる問題は解決できません。

public class MyClass
{
    // 必須
    public int Property1 { get; }
    public string Property2 { get; }

    // オプション
    public int? Property3 { get; set; }
    public string Property4 { get; set; }

    public MyClass(int property1, string property2)
    {
        if (property1 == 0)
        {
            throw new InvalidOperationException("Property1が不正です。");
        }

        if (property2 == null)
        {
            throw new InvalidOperationException("Property2が不正です。");
        }

        Property1 = property1;
        Property2 = property2;
    }
}

var myClass = new MyClass(1, "a")
{
    Property3 = 2,
    Property4 = "b"
};

2. ビルダーパターンを使用する

ビルダーパターンを使用してインスタンスを生成する方法です。
コンストラクタが膨れ上がる問題は解決できますが、プロパティが多いとコード量が多くなります。

public class MyClassBuilder
{
    private int property1;
    private string property2;
    private int? property3;
    private string property4;

    public MyClassBuilder WithProperty1(int value)
    {
        property1 = value;
        return this;
    }

    public MyClassBuilder WithProperty2(string value)
    {
        property2 = value;
        return this;
    }

    public MyClassBuilder WithProperty3(int value)
    {
        property3 = value;
        return this;
    }

    public MyClassBuilder WithProperty4(string value)
    {
        property4 = value;
        return this;
    }

    public MyClass Build()
    {
        if (property1 == 0)
        {
            throw new InvalidOperationException("Property1が不正です。");
        }

        if (property2 == null)
        {
            throw new InvalidOperationException("Property2が不正です。");
        }

        return new MyClass(property1, property2, property3, property4);
    }
}

var myClass = new MyClassBuilder()
    .WithProperty1(1)
    .WithProperty2("a")
    .WithProperty3(2)
    .WithProperty4("b")
    .Build();

3. 引数をクラスにする

引数をクラス化する事でコンストラクタをシンプルにできます。
ただしクラスの追加が必要になります。

public class MyClass
{
    public int Property1 { get; }
    public string Property2 { get; }
    public int? Property3 { get; set; }
    public string Property4 { get; set; }

    public MyClass(MyClassParams parameters)
    {
        Property1 = parameters.Property1;
        Property2 = parameters.Property2;
        Property3 = parameters.Property3;
        Property4 = parameters.Property4;
    }
}

public class MyClassParams
{
    public int Property1 { get; set; }
    public string Property2 { get; set; }
    public int? Property3 { get; set; }
    public string Property4 { get; set; }

    public MyClass(MyClassParams parameters)
    {
        if (parameters.Property1 == 0)
        {
            throw new InvalidOperationException("Property1が不正です。");
        }

        if (parameters.Property2 == null)
        {
            throw new InvalidOperationException("Property2が不正です。");
        }

        Property1 = parameters.Property1;
        Property2 = parameters.Property2;
        Property3 = parameters.Property3;
        Property4 = parameters.Property4;
    }
}

var myClassParams = new MyClassParams
{
    Property1 = 1,
    Property2 = "a",
    Property3 = 2,
    Property4 = "b"
};

var myClass = new MyClass(myClassParams);

未分類

Posted by ababa