見出し画像

#6 Javaプログラミングデザイン考4

メソッドへ渡す最適な引数の数は

今回は、メソッドに渡す引数はどの様なものをいくつ渡すのが適切なのかということについて考察していきます。エンジニアのこだわりや好みによって分かれるところがありますが、これに関しては明確な答えと理由があり、次から順次説明をしていこうと思います。

機能追加・変更での安易な改変

ほぼ似通った処理だから新たにメソッドを作るのはもったいない、でも必要なデータが足りないからそのままでは使えない。こんな場面に遭遇した場合、さして考慮せずに引数を追加したりしていないでしょうか。
(といっても影響範囲ぐらいは確認しているでしょうが)
そんな事の繰り返しで、あともう1個、あともう1個と追加し続けた結果、とんでもない数の引数を受け取るメソッドが完成してしまうのです。
下に例となるメソッドのサンプルを載せましたが、私がこれまで遭遇したプログラムと比較するとまだ可愛い方です(笑)

/**
 * 顧客情報登録.
 * @param customerId 顧客ID
 * @param cstAddrJisCd 住所JISコード
 * @param cstTelNo 電話番号
 * @param cstCompanyCd 所属企業コード
 * @param cstBankCd 所有口座銀行コード
 * @param cstAccNo 所有口座番号
 * @param cstCardCd 所有クレジット会社コード
 * @param cstCardNo 所有クレジットカード番号
 * @param cstRentKbn 持ち家/賃貸区分
 * @param isSpouse 配偶者有無
 * @param isChildren 子供有無
 */
public void RegistCustomerIinfo (
        String custmerId
      , String cstAddrJisCd
      , String cstTelNo
      , String cstCompanyCd
      , int cstBankCd
      , int cstAccNo
      , int cstCardCd
      , int cstCardNo
      , int cstRentKbn
      , boolean isSpouse
      , boolean isChildren
    ) {
 ...
}

こういったメソッドにはどういった問題が内在するのか、これまでの経験から、次のような点が考えられます。

1.可読性が下がる

どれほどインデントを駆使したところで、可読性が下がることは避けれらません。サンプルのように1行にひとつ引数を記述した場合、それだけで何行も使ってしまう上、JavaDocコメントを記述したら画面に見えるのはコメントと引数だけ、なんてことにもなりかねません。

2.メンテナンス難度の増大

機能を追加した時は確かに必要であった引数も、メソッドの改修により不要となることも往々にしてあることですが、その時確実に引数へ目が行き届いているかは別の話。解析作業でソースを追ってみると受け取る引数の半分がいらない状態だった、なんてことも特殊な事例ではありません。また、サンプルのようにメソッド概要のコメントが漏れなく記述されている場合はよいが、コメントが改修に合わせて書き換えられていない(嘘コメント状態)、そもそも説明がない、となった場合は、引数の正体を探るため呼び出し元を解析する手間が、それも相当上位から引き継がれてきたものならば探索範囲がどんどん広がっていきます。
※コメントの重要性については過去記事でも触れました。

3.同型が連続する引数=トラップ

サンプルでも引数の型が1~4個目まではString型、5~9個目はint型、10、11個目はboolean型と同型の引数が連続で並んでいます。
この様な場合に起こるトラブルのひとつとして、同型の引数にうっかり「入れ子で変数を代入する」というミスが考えられます。
当然この様な場合はコンパイルエラーは起こりません。さらにタチの悪いことに、「正常動作するものの想定結果とは異なる動きをする、うまくいくこともあればいかないこともある。不具合の発生パターンがすぐに掴めない」といった状況に陥ることが往々にしてあり、バグ解析にかなりの時間を浪費することに繋がっています。

メソッドに多くの引数を渡す方法

とはいえ、メソッドにさせる処理によっては多くのデータを引き渡す必要のある場面というのはごく普通のことで、安全に多くの変数を渡すために考え出されたのが「コンテナクラス」になります。
コンテナクラスという名称は、エンジニア各位が働く現場によって異なる呼び方をしているかも知れません(これまで筆者が経験したのはフォーム、トランク、エンティティ)が、構成はどれも同じ、private変数ひとつに対し、変数から値を取得するgetterメソッド、変数に値を格納するsetterメソッドの組み合わせ。それが必要なデータ数分定義されています。
下の例ではString型の変数3つを定義しています。

/**
 * 顧客情報コンテナ.
 */
public class CustomerContainer (

    /** 顧客ID */
    private String customerId = null;
    /** 住所CD */
    private String cstAddrJisCd = null;
    /** 電話番号 */
    private String cstTelNo = null

    /**
     * 顧客IDを取得する.
     * @return 顧客ID
     */
    public String getCustomerId() {
        return this.customerId;
    }

    /**
     * 顧客IDを設定する.
     * @param customerId 顧客ID
     */
    public void setCustomerId(String customerId) {
        this.customerId = customerId;
    }

    /**
     * 住所CDを取得する.
     * @return 住所CD
     */
    public String getCstAddrJisCd() {
        return cstAddrJisCd;
    }

    /**
     * 住所CDを設定する.
     * @param cstAddrJisCd 住所CD
     */
    public void setCstAddrJisCd(String cstAddrJisCd) {
        this.cstAddrJisCd = cstAddrJisCd;
    }

    /**
     * 電話番号を取得する.
     * @return 電話番号
     */
    public String getCstTelNo() {
        return cstTelNo;
    }

    /**
     * 電話番号を設定する.
     * @param cstTelNo 電話番号
     */
    public void setCstTelNo(String cstTelNo) {
        this.cstTelNo = cstTelNo;
    }

1.コンテナにすることのメリット

一番のメリットは、変数の追加による影響が皆無であることです。つまり、コンテナを利用する処理すべてを検証する必要がないということです。

次に、どれだけの数の変数を定義しようとも、記述が長大にならないため視認性の高いソースコードを維持できる点も優位な点と言えます。

2.コンテナのデメリットはないのか

クラス内に変数を定義するため、ブラックボックス化とも言えなくはないと思いますが、(筆者の体感で)デバッグ業務でもさして不便は感じないため、デメリットであるとは言いにくいかも知れません。

結局のところ最適な引数とは

Javaプログラムが実行する処理において使用する引数とは、突き詰めていくとデータベースに格納されたデータであることに異論はないと思います。
であるならば、取得したデータの1レコードをコンテナに詰めることがもっとも適したデータの受け渡し方法ではないかと考えます。

  • データベースから取得した1レコードであることが確定できる

  • 取得後の処理を実行するのにベースとなる情報が網羅されている

  • これ以外に必要な情報は、レコードのデータをもとに加工、算出、または再度DBアクセスで取得できるものに限定されるはず

ばらばらに保管した変数では、いつデータを格納したのか、今何の値が入っているのか、常に意識しておかなければなりませんが、コンテナであればそれもあまり気にする必要はありません。

今回はここまでといたします。

今回のまとめ

  • メソッドに多くの引数を渡すと可読性が落ちメンテナンスの難度が上がる

  • 同型の引数が連続する渡し方は、入れ子で渡す恐れがありバグの元となる

  • コンテナクラスはメソッドに多くの引数を渡すのに適している

いいなと思ったら応援しよう!