メソッドの引数に指定するものは、オブジェクト全体とオブジェクト一部のどちらが良いですか?
問
引数を必要とするメソッドを定義してください。
定義するメソッドの引数は、呼出す側が持つオブジェクトの一部の要素だけを必要とします。
その時、メソッドの引数として、次のどれかを選び、理由を説明してください。
- 呼出す側が持つオブジェクト全体
- 呼出す側が持つオブジェクトのうち必要とする一部の要素
- その他
理由の観点は、凝集度/結合度/保守性/可読性/個人的趣味など、一定の支持が得られるものであれば自由とします。
また、プログラミング言語固有の書き方を元に理由とする場合、対象のプログラミング言語も指定してください。
背景と説明
先日、メソッドの引数としてオブジェクト全体とオブジェクト一部、どちらが良いのか、という話がありました。
対象は JavaScript (Node.js) です(が、どのようなプログラミング言語でも通じるかなと思い、あえてタグ付けはしていません)。
登場人物は、以下の通りです。
-
use_child
メソッド:child
オブジェクトを用いて処理を実行するメソッド。ただし、将来的にもchild
オブジェクトだけを見ればいいだけと断定はできない(かなり不明瞭) -
main
メソッド:use_child
メソッドを呼出すメソッド。use_child
以外の、parent
オブジェクトが保持するオブジェクトを処理するメソッドを呼出す -
child
オブジェクト:use_child
メソッドが処理に必要とするオブジェクト -
parent
オブジェクト:child
オブジェクトを保持するオブジェクト。プログラミング言語のコア機能で生成される(ため、このオブジェクト自体の修正は難しい)。child
オブジェクト以外にも多くのオブジェクトを持ち、それぞれの階層はバラバラである
私は、下のようなソースコードのようが好きです。
function main() {
// 呼出し側が持つオブジェクト
const parent = {
child: "wanna use item" // 存在保証は無い
}
// 問題のメソッド呼出し
use_child(parent)
}
function use_child(parent) {
// parent.child のバリデーションチェック
const child = parent.child
// child を用いた処理
}
理由は、次の点です。
-
main
メソッドに、parent.child
のバリデーションチェックをしてほしくない-
use_child
メソッドを呼出す側でparent.child
の存在判定や正常判定などをするのは、責務として違う(気がする) -
parent.child
の場所が変わった場合、use_child
メソッドではなくmain
メソッドを修正する必要があるため、凝集度が下がる(気がする) -
main
メソッドにはuse_child
以外にもメソッドがあるため、main
メソッドでのバリデーションチェック処理が肥大化する(気がする)
-
- (
main
メソッドに限らず)呼出し側がuse_child
メソッドの実装を理解する必要がない-
use_child
メソッドでparent.child
を呼出していることを、呼出し側が理解して引数に入れるべきではない
-
一方、レビュアーからは、次のコードを提案されました。
function main() {
// 呼出し側が持つオブジェクト
const parent = {
child: "wanna use item" // 存在保証は無い
}
// parent.child のバリデーションチェック
// 問題のメソッド呼出し
use_child(parent.child)
}
function use_child(child) {
// child を用いた処理
}
理由は、次の点です。
-
main
メソッドとuse_child
メソッドの結合度を下げたい - JavaScriptでは
parent.child
が存在しない場合でも、呼出し自体は実行時エラーとならないため、use_child
メソッド内でchild
のバリデーションチェックを行うだけで良い
結局、そこまで大きな問題とはならないだろうということで、話自体は終わりましたが、実際のところ、どっちがいいのかモヤモヤしていたので、質問してみました。
個人的には、両者言い分は間違っていないと思っています。
そのため、片方を糾弾するような答えは控えていただけると助かります。
自分の主張の方が正しい!ということを言いたいわけではありません。
わかりづらい点などありましたら、追加で説明させていただきます。