Closed26

オブジェクト指向

daijiro maeyamadaijiro maeyama

設計の実用的な定義

プログラマーは超能力者ではないので、特定の未来を予測した設計は、たいてい失敗に終わる。
実用的な設計とは、未来を推測するものではなく、未来を受け入れるための選択肢を保護するもの。選択してしまうのではなく、動くための余地を設計者に残すもの。
設計の目的は「あとにでも」設計できるようにすることであり、その第一の目標は変更コストの削減。

daijiro maeyamadaijiro maeyama

クラスが単一責任がどうか見極める

クラスの持つメソッドを質問に言い換えたときに、意味を成す質問になっているべき。
また、1文でクラスをかんたんに説明できるものであるべき。
クラス内のすべてがそのクラスの中心的な目的に関連していれば、そのクラスは凝集度が高い、もしくは単一責任であると言われる。

daijiro maeyamadaijiro maeyama

あらゆる箇所を単一責任にする

メソッドに対しても役割が何であるか質問をし、また1文で責任を説明できるようにする。これはクラスを明確にする効果がある。

daijiro maeyamadaijiro maeyama

クラスの唯一の目的が、他のクラスのインスタンス作成であるオブジェクトをオブジェクト指向設計では、「ファクトリー」という。

つまり、ほかのオブジェクトを製造するオブジェクトはファクトリーです。

daijiro maeyamadaijiro maeyama

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

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

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

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

アプリケーションにおいて、「データ」と「振る舞い」の両方を兼ね備えた「名詞」を表すものをドメインオブジェクトと呼ぶ。ドメインオブジェクトとは、大きくて目に見える現実世界のものを表し、かつ最終的にデータベースに表されるもの。

daijiro maeyamadaijiro maeyama

基本的な設計の質問を、「このクラスが必要なのは知っているけれど、これは何をすべきなんだろう」から、「このメッセージを送る必要があるけれど、だれが応答すべきなんだろう」へ変えることが、キャリア転向への第一歩。
オブジェクトが存在するからメッセージを送るのではなく、メッセージを送るためにオブジェクトは存在する。

daijiro maeyamadaijiro maeyama

あえてキーワードを省略し、代わりにコメントやそれ用の命名規則を使い、インターフェースの「パブリック」と「プライベート」な部分を示している (たとえば Ruby on Rails では、プライベートメソッドの先頭に _ を付ける)。

daijiro maeyamadaijiro maeyama

コンテキストを最小限にする

パブリックインターフェースを構築する際は、そのパブリックインターフェースが他者に要求するコンテキストが最小限になることを目指す。「何を (what)」と「どのように (how)」の違いを常に念頭に置き、メッセージの送り手が、クラスがどのようにその振る舞いを実装しているかを知ることなく、求めているものを得られるようにつくる。

daijiro maeyamadaijiro maeyama

デメテルの法則

オブジェクトを疎結合にするためのコーディング規則の集まり。
「ドッドは1つしか使わないようにしよう」なんて言い方もされる。

daijiro maeyamadaijiro maeyama

パブリックインターフェースに含まれるメソッドは、次のようにであるべき。

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

ダックタイプはいかなる特定のクラスとも結びつかないパブリックインターフェース。

daijiro maeyamadaijiro maeyama

ダックで置き換えられるもの。

  • クラスで分岐する case 文
  • kind_of? と is_a?
  • responds_to?
daijiro maeyamadaijiro maeyama

Rails の Concern で使われるモジュール名は ***able となっているものが多い。
あくまで慣習であり、規約ではない。

daijiro maeyamadaijiro maeyama

以下のアンチパターンを目にしたときは、継承を使ってコードを改善できないか疑ってみる。

1. オブジェクトが type や category という変数名を使い、どんなメッセージを self に送るかを決めているパターン

オブジェクトの関連度は高いものの、わずかに型の異なるオブジェクトが含まれている。共通のコードは抽象スーパークラスにおき、サブクラスを使って異なる型をつくる。このような構成にすると、サブクラスを追加することで新たなサブタイプ (派生型) をつくれる。これらのサブクラスが、既存のコードを変えずに階層構造を把握してくれる。

2. メッセージを受け取るオブジェクトのクラスを確認してから、どのメッセージを送るかをオブジェクトが決めているパターン

ダックタイプを見落としてしまっている。この場合、受けてになり得るオブジェクトは、どれも共通のロールを担っている。このロールはダックタイプとしてコードに落とし込まれるべき。そうすれば、受け手のオブジェクトが複数あったとしても、送り手のオブジェクトとしてはどのオブジェクトに対しても1つのメッセージを送るだけで済む。

daijiro maeyamadaijiro maeyama

コンポジションでは、オブジェクト間の関係をクラスの階層構造としてコードに落とし込むことはしない。コンポジションでは、オブジェクトは独立して存在する。そしてその結果、オブジェクトはお互いについて明示的に知識を持ち、明示的にメッセージを委譲する必要がある。コンポジションによって、オブジェクトは構造的に独立して存在できるようになる。しかし、それは明示的なメッセージ委譲のコストを払ってのこと。

daijiro maeyamadaijiro maeyama

継承とコンポジションの利用について

  • 継承とは、特殊化のこと
  • 継承が最も適しているのは、過去のコードの大部分を使いつつ、新たなコードの追加が比較的少量のときに、既存のクラスに機能を追加する場合
  • 振る舞いが、それを構成するパーツの総和を上回るのなら、コンポジションを使う
daijiro maeyamadaijiro maeyama

継承を使った結果得られるコードは「オープン・クローズド (Open-Closed)」と特徴付けられる。階層構造は、拡張には開いており (open)、修正には閉じている (closed).

daijiro maeyamadaijiro maeyama

リファクタリングとは、ソフトウェアの外部の振る舞いを保ったままで、内部の構造を改善していく作業を指す

daijiro maeyamadaijiro maeyama

受信メッセージはオブジェクトのパブリックインターフェースの一部であるので、テストされなければならない。

daijiro maeyamadaijiro maeyama

最も良いテストとは、対象のコードと疎結合であり、すべてに対して一度だけテストをし、そしてそれが適切な場所で行われているもの。

daijiro maeyamadaijiro maeyama

リスコフの置換原則 (LSP)

「サブクラスはスーパークラスと置換可能でなければならない」という原則。
つまり、派生クラスは基底クラスを継承するときに、常に基底クラスの挙動を一切変えないようにすべきであるということ。

このスクラップは2022/12/25にクローズされました