1.設定が必須ではない引数(パラメーター:設定値)をとる処理の定義
これは、クラスとチェーンメソッドを利用して定義するのがよいなと思っています。
GoやNimの場合、構造体をレシーバ変数として定義する関数にあたると思います。
たとえば、CSVを読み込む処理で、区切り文字を変更したり、文字コードを変更したりする場合を考えます。
コードは、PHP(7.4以降)で書いてみます。
具体的な処理実装はせず、インターフェース(呼び出し部分)のみ定義します。
namespace Csv;
class Reader {
private string path;//ファイルパス
private string delimiter = ',';//区切文字
private string charset = 'utf-8';//
//必ず設定する引数はコンストラクタの引数で設定
public function __construct(string $path) {
$this->path = $path;
}
public function setDelimitery(string $value) : self {
$this->delimiter = $value;
return $this;//自らの参照を返し、チェーンメソッドにして、別のセッターを呼び出せるようにする。
}
public function setCharset(stirng $value) : self {
$this->charset = $value;
return $this;
}
public function getLines() : array {
//ファイルから行を読み込む処理
return $lines;
}
}
今回例にした場合だと、getLinesにすべての引数を持たせるのも良いかもしれません。
個人的に、引数が多くなること、また、必ず設定しない引数を定義することは以下のようなデメリットがあると考えます。
・引数が多いのは、その関数の関心が多く、処理が複雑になっている。
・必ず使わない引数を設定すると呼び出し側が悩み、ときに、バグを生むことになる。
引数は、0-2個ですべて必須がベストだと個人的には考えます。それゆえ、任意の設定値が増える場合は、クラスとチェーンメソッドを使った方が、変更しやすく無駄のない呼び出しができると考えます。
では、呼び出しのコードを記載します。
use Csv\Reader;
//文字コードのみ変更する場合。
$lines = (new Reader('任意のファイルパス'))->setCharset('shift-jis')->getLines();
foreach($lines as $line {
echo $line;
}
//全く変更をしない場合
$lines = (new Reader('任意のファイルパス'))->getLines();
上記のように、設定値の要不要に応じて、メソッドを呼び出したり、呼び出さなかったりすることで臨機応変に処理を実行します。
必ず実行する処理の引数の設定は不定になります。
この方がきれいな実行であるし、変更にも強いと思います。
昔、ある現場で、10個以上の引数をとるメソッドがあって、変更が大変なのを経験して、引数が多いのは悪と身にしみて感じました。
2.簡易的なビルダーパターン
上記の方法は、デザインパターンでいえば、ビルダーパターンに近いと思います。
ただ、インターフェースを用いた抽象化などは行わないので、厳密にはビルダーパターンと少し違うかもしれません。
ビルダーパターンだけではないのですが、デザインパターンは「抽象化」を念頭においた設計が多く、そこまで考えるとややオーバースペックだなと感じるところもあります。
デザインパターンのエッセンスのみを抽出して、簡易的に変更に適応しやすい設計をするのもよいかと思います。
3.抽象化とは異なる領域でのクラスの使いこなし
最近、オブジェクト指向への反発から、クラスを使うことを避ける動きもあり、なんでも関数で定義しようとする人もいるかもしれません。ただ、みたように関数の引数を増やすことは読みにくい、呼び出しにくいなどの可読性でデメリットがあります。
また、プログラム改修においても問題を起こすことがよくあります。
オブジェクト指向への反発は、抽象的な設計をしてわかりにくさを招くことをその起因としていると思います。
ただ、それはクラスを使うことと必ずしも同じではありません。
クラスは、ここで見たように、処理レベルでの関心を分離し、クラス全体で複雑な処理を定義するには向いていると感じます。
もちろん、Go、Rust、Nimなどではクラスではなく、構造体をつかって同じような定義ができます。
プログラムは、単純に定義していくこと、呼び出すことで問題を回避できると思います。クラスは無用な混乱を招くものではなく、単純化に役立つ有用な文法であると感じます。