見出し画像

【オブジェクト指向】「4つの依存」とその対応について

今回は、依存関係を理解し、どのように疎結合のコードを作っていくのかについて見ていきます。

こちらの記事は、

「オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方」第3章の内容を説明しています。

とてもためになる本だと思いますので、興味を持っていただいた方は、ぜひ本書も手に取って見てください。

では、始めていきましょう。

0 今回注目する箇所について

今回は、下の2つのGearクラスWheelクラスを見ていきます。

自転車関係のコードです。

また、依存関係について見ていきたいのは下の箇所です。

では、具体的に見ていきましょう。

1 依存関係を理解する

まずは今回のコードの依存関係を理解しましょう。

1ー1 今回注目する箇所の内容

「 gear_inches」メソッドは、下のように、

① Wheelクラスのインスタンスを作って、
② diameterメソッドを実行

しています。

1ー2 4つの依存を認識する

実はここで、Gear4つの点について、Wheel依存してしまっています。

どこで依存しているのでしょう。

1ー2ー1 他のクラス名への依存

まずは、gear_inchesメソッドは「Wheel」という名前に依存しています。

これでは、「Wheel」クラス名が変わったら、動かなくなってしまいますね。

でも、実はもっと大きい問題があるんです。

それは、このメソッドは「Wheel」のdiameter(直径)についてしか計算しないと言っていることになるからです。

これでは、仮に「Disc」というdiameterを持つクラスが登場したとしても、対応することができません。

1ー2ー2 メッセージの有無についての依存

このメソッドはWheelが「diameter」に応答してくれるということも知っています。

これも依存ですね。

1ー2ー3 必要な引数の依存

下のようにインスタンス化する過程で、引数を渡しています。

つまり、Wheelに2つの引数が必要であることを知っているのですね。

1ー2ー4 引数の順番の依存

最後に、引数を2つ以上渡す時、この順番で渡すということも知っています。

これも依存ですね。

2 疎結合なコードを書く

2ー1 依存オブジェクトの注入(dependency injection)

まず見ていきたいのが「依存オブジェクトの注入」の手法です。

下のように、Gearクラス内からWheelクラスのインスタンス化が消えました。

これは、インスタンス化の部分クラスの外に出したためです。

中身を具体的に見てみると、「gear_inches」というメソッドは「wheel」「diameter」に応答するということは知っています。

しかし、「rimやtireを使って計算する」というような依存からは切り離されました。

GearクラスWheelクラスを知るという責任から大きく解放されました。

2ー2 依存を隔離する

上のように「依存オブジェクトの注入」までできないケースもあります。

その場合も、クラス内で依存を隔離することにより、改善を行うことが可能です。

2ー2ー1 初期化部分に隔離する

元々は「gear_inches」メソッド内にあったインスタンス化初期化部分に隔離しています。

これによって、依存が明確になりました。

しかし、これには問題もあります。

それは初期化を通じて、「必ず」Wheelクラスのインスタンスができてしまうということです。

つまり、Gearクラス必ずWheelのインスタンスを持つことになります。

2ー2ー2 独自のメソッド内に隔離する

下のように、インスタンス化の部分を独自のメソッドにすることで、「wheelインスタンスが必要な場合は作る」という関係にできます。

つまり、wheelが使われない場合は、Wheelのインスタンスが作られなくなるので、依存が減ります。

なお、wheelメソッド内では、nilガード(||=)が使われているので、@wheelがnilである初回時だけ、インスタンス化が実行されます。

2ー2ー3 外部メッセージを隔離する

では、少し違う観点からも隔離について見ていきましょう。

下の「diameter」は自身のクラスではない、「Wheel」クラスのインスタンスにメッセージを送っています。

外部にメッセージを送っているので、外部メッセージです。

ということは、外部である「Wheel」クラス「diameter」というメソッド名が変更されてしまえば、動かなくなってしまいます。

上の場合は見やすいですが、下のように、前後にたくさんの処理が走っていたり、いろいろなところで使われていたらどうでしょう。

修正するのは大変そうです。

こんな時は、外部メッセージを使う部分を下のように隔離しましょう。

これであれば、「gear_inches」は自身の「diameter」メソッドにメッセージを送るようになりました。(外部に送っていません

ということは、仮に外部であるWheelクラス「diameter」という名前が変更になっても、隔離された「diameter」メソッドだけを直せば良くなりました。

いかがでしたでしょうか。

みなさんが依存の少ないコードを書く上での一助になれば幸いです。

サポートをしていただけたらすごく嬉しいです😄 いただけたサポートを励みに、これからもコツコツ頑張っていきます😊