佐々木屋

技術的なことから趣味まで色々書きます

クラスを考える⑤(メソッドの引数とプロパティ)

VB6で何かメソッド(サブプロシージャ)を作成する場合、public変数を用意するか引数を持たせるかになると思います。オーバーロードはありませんので、非常に冗長な関数群が出来るのが特徴です(但し仕様上そちらの方が効率的な場合もあります)。

オブジェクト指向においては、オーバーロードは使えますが、それ以前に静的クラスで無ければインスタンスを作成できますので、積極的にメンバー変数やプロパティを使って簡潔なメソッドを作成した方が良いです。

では、どういった判断でプロパティにするのか、メンバー変数にするのか、引数にしたらよいのでしょうか。

メソッドの引数は「オペランド(操作対象)」と「オプション(モード)」の2種類あります。引数は極力オペランドのみにすべきです。もっと分かりやすく言えば、省略できる引数やほとんど1種類の既定値で事足りるような引数はオプションなのでそれはプロパティとし、毎回指定する必要があり、且つそのメソッドのみに適用されるような場合は引数にします。

なぜ、オプションを引数にしてはいけないか、私が考える理由は以下の通りです。



例えば、たい焼きの話で考えてみます。
「焼く」というメソッドを作る場合、以下のメンバーが考えられます。

  • 中身(あんこ、チョコ、クリーム・・・etc)
  • 焼く時間
  • 出来上がり(成功か失敗)

そうすると、「焼く時間」は恐らく一定で既定値がありそうなのでオプションとなります。「出来上がり」はメソッドの戻り値として設定します。
「中身」はオプションとオペランドどちらで取っても構いませんが、呼び出し元が複数連続して使用する(焼く)可能性が考えられるので、オプションにした方が汎用性がありそうです。

//たい焼きクラス
public class たい焼き {
    public string 中身 { private get; set; } = "あんこ";
    public int 焼く時間 { private get; set; } = 5;

    public bool 焼きます() {
        try {
            //中身、焼く時間を使って焼く処理を記述
            return true;
        }
        catch {
            return false;
        }
    }
}

//あんこを5分の焼き時間で5個焼く場合
public static void Syori1() {
    たい焼き taiyaki = new たい焼き();
    for (int i = 1; i <= 5; i++) {
        Console.WriteLine(taiyaki.焼きます());
    }
}

//11時台だけクリームを5分の焼き時間で5個焼く場合
public static void Syori2() {
    たい焼き taiyaki = new たい焼き();
    if (DateTime.Now.Hour == 10) taiyaki.中身 = "クリーム"; //←この1行を入れればOK
    for (int i = 1; i <= 5; i++) {
        Console.WriteLine(taiyaki.焼きます());
    }
}


しかし、このメンバーが全て引数にした場合どうなるでしょうか。

public class たい焼き {
    public bool 焼きます(string 中身,int 焼く時間) {
        try {
            //中身、焼く時間を使って焼く処理を記述
            return true;
        }
        catch {
            return false;
        }
    }
}

//あんこを5分の焼き時間で5個焼く場合
public static void Syori1() {
    たい焼き taiyaki = new たい焼き();
    for (int i = 1; i <= 5; i++) {
        Console.WriteLine(taiyaki.焼きます("あんこ",5));
    }
}

//11時台だけクリームを5分の焼き時間で5個焼く場合
public static void Syori2() {
    たい焼き taiyaki = new たい焼き();
    string nakami = "あんこ";                                            //←これを追加
    if (DateTime.Now.Hour == 10) nakami = "クリーム"; //←これを追加
    for (int i = 1; i <= 5; i++) {
        Console.WriteLine(taiyaki1.焼きます(nakami, 5));
        //以下だと変数不要で1行で済むが、都度条件判断が必要
        //Console.WriteLine(taiyaki2.焼きます(DateTime.Now.Hour == 10 ? "クリーム" : "あんこ", 5));
    }
}


たい焼きクラス自体はシンプルに作られていますが、呼び出し元がこのように無駄に長い、可読性が悪いコードになってしまいます。特に引数にあたる部分の変化があるようなプログラムだと尚更です。これではクラス化する意味がありません。