This page looks best with JavaScript enabled

『オブジェクト志向設計実践ガイド』4章

 ·  ☕ 5 分で読めます

4章

インターフェースを定義する

クラスが何を「するか」ではなく、何を「明らかにするか」。
他のオブジェクトから呼び出すことのできるメソッド=晒されたメソッドによって構成されるのが、クラスのパブリックインターフェースである。

パブリックインターフェース

  • クラスの主要な責任を明らかにする
  • 外部から実行されることが想定される
  • 気まぐれに変更されない
  • 他者がそこに依存しても安全
  • テストで完全に文書化されている

お客さんから厨房に対する「〇〇を注文する」→「〇〇が提供される」
インターフェースは注文を伝える店員さんのようなポジション。

単一責任の原則に従うと、パブリックメソッドはクラスの責任を説明するものになるはず。
メソッドは以下のようになるべきである。

  • 明示的にパブリックインターフェースであると特定できる
  • 「どのように」よりも、「何を」になっている
  • 名前は、考えられる限り、変わり得ないものである
  • オプション引数として、ハッシュをとる

プライベートインターフェース

  • 実装の詳細に関わる
  • 他のオブジェクトから送られてくることは想定されていない
  • どんな理由でも変更されうる
  • 他者がそこに依存するのは危険
  • テストでは、言及さえされないこともある

厨房で行われること。「材料を用意する」「〇〇を焼く」など。

パブリックインターフェースを見つける

ユースケース
「参加者は、旅行を選ぶために、適切な難易度の、特定の日付の、自転車を借りられる旅行の一覧を見たい」

ドメインオブジェクト(本書特有の言葉?)
「データ」と「振る舞い」の両方を兼ねた「名詞」
大きくて目に見える現実世界のものを表し、最終的にデータベースに表されるもの。

大事なのは、ドメインオブジェクトそのものではなく、オブジェクト間のメッセージのやり取りである。

シーケンス図

シーケンス図は、Unified Modeling Language(UML)で定義されている。
処理の流れの中のオブジェクト間のメッセージのやり取りを表す。

メッセージを中心としてクラスの責任を考えていくことが設計者としては重要。
「クラスが何をすべきか」→「このメッセージは誰が応答すべきか」の思考の転換。

public, protected, private

Ruby の private と protected 。歴史と使い分け - Qiita

private

Tripクラスのprivateメソッドfun_factorは、Trip内からself.fun_factorを送ることも、他のオブジェクトからa_trip.fun_factorを送ることもできない。
Tripのインスタンスとそのサブクラスの内部から、自分が受けるfun_factorは受け取ることができる(自分と身内→自分はOK)。

protected

受け手がself、もしくはselfと同じクラスかそのサブクラスのインスタンスである場合にのみ、受け手を明示できる。
self.fun_factora_trip.fun_factorも送ることができる。

public

どこからでも見ることができる。

デメテルの法則

オブジェクトを疎結合にするためのコーディング規約。
3つ目のオブジェクトにメッセージを送るときに、異なる型の2つ目のオブジェクトを介すことを禁ずる。
「直接の隣人にのみ話しかけよう」「ドットは1つしか使わないことにしよう」

customer.bicycle.wheel.tire(属性)とかcustomer.bicycle.wheel.rotate(振る舞い)とかは駄目。
hash.key.sort.join('')はオーケー。
hash.keyはEnumerableを返し、hash.key.sortもEnumerableを返し、hash.keys.sort.joinはStringを返す。複数のStringからなるEnumerableであると認めれば、中間のオブジェクトはすべて同じ型を持つので大丈夫。

解消するために

移譲
他のオブジェクトにメッセージを渡すこと。
しばしばラッパーメソッドを介して行われる。

継承とは別物らしい。

Rubyではdelegate.rbやforwardable.rbがある。Railsではdelegateメソッドがある。

Rubyのdelegateについて整理する - 10nin blog
delegateを使って、別クラスへの切り出し - Qiita
railsでデメテルの法則を守るためのdelegateメソッド - BlueTechNote

移譲は万能薬ではない。結合を隠しているだけで、つながりそのものはまだあるため。
customer.bicycle.wheel.rotatecustomer.rideとして表すと一般化できる。

合っているのかわからないゾーン

p.98〜106らへん
意味わからんので、思考の切れ端を置いておく。


Tripは「旅行を準備されること」を望んでいるが、自転車が整備されることはTripの管轄外。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Customer
  def order(いろいろな条件)
    TripFinder.suitable_trips
  end
end

class TripFinder  # 適切な旅行を見つける
  def suitable_trips(on_date, of_difficulty, need_bike)
  end
end

class Trip
  def suitable(on_date, of_difficulty)
  end
end

class Bicycle
  def suitable(trip_date, route, type)
    
  end
end

ユースケース
「参加者は、旅行を選ぶために、適切な難易度の、特定の日付の、自転車を借りられる旅行の一覧を見たい」

図4.8

Customer→TripFinder「条件を提示するから旅行の一覧をください」
TripFinder→Trip「(日程、難易度などTrip自身の)条件に合う旅行一覧をください」→Trip「あいよ」
TripFinder(おー、いろいろ来たなあ。それぞれの旅行の条件について自転車を用意できるか聞くか)
TripFinder→Bicycle「(旅程、ルートの)条件に合わせて自転車を準備できますか?」→Bicycle「準備できるよ / できないよ」
TripFinder(用意できるものだけリストアップするか)
TripFinder→Customer(レスポンス)「これが一覧やで」

Share on

aiandrox
Written by
aiandrox
今日も楽しく明日も楽しく

目次