オブジェクト指向の法則集

  • 1041
    いいね
  • 1
    コメント

この記事は、故石井勝さんが1999年に書いた記事を Qiita に転載するものです。オブラブ(objectclub.jp)にて記事をホスティングしていましたが、現代でも十分に読める内容なので、たくさんの方に読んでもらいたいと思い、若干の編集(リンクとコンテキスト追加)を平鍋が行い、転載します。今でも、読みやすく、カジュアルな語り口のよい記事です。

なお、この記事の他にも石井さんのオブジェクト指向やRubyに関する多くの記事をオブラブの「まさーるのページ」で読むことができます。では、以下に石井勝さん(旧メールアドレス masarl@nifty.com)の記事を転載します(平鍋)。

はじめに

ここでは,オブジェクト指向に出てくる法則・原則をまとめました.パターンに比べてほとんど知られていないのが現状ですが,優れたオブジェクト指向開発者を目指すならデザインパターンよりまずこっちを理解し覚えてしまいましょう.

これらの法則は,絶対守らなければならないというものではありません.開発中に法則が守られているか意識することが重要です.つまり

  • 今行っている設計はその法則が守られているだろうか
  • その法則を破っている場合,破るべき正当な理由があるだろうか

と絶えず考えるようにしましょう.そうするとそれは自然に優れたオブジェクト指向設計になるのです.つまりこれらの法則は,優れたオブジェクト指向開発のための指針なのです.

Robert C. Martin の Principles of OOD

Robert C. Martinは,オブジェクト指向設計の指針になる法則集を`Principles of OOD'の形でまとめています.以下は彼のC++ Report連載記事から引用しました.Object MenterからPrinciples of OOD関連のアーティクルはすべて入手できます.

(編集者注: この Principles of OOD は後に書籍『アジャイルソフトウェア開発の奥義』の中で解説され、その後、"SOLID"という名前で整理されて、たくさんの周辺記事が出ています。

)

The Open-Closed Principle (OCP)

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

Bertrand Meyer先生の有名なOCPです.OOSCの訳本では,「開放/閉鎖原則」となっていますが,難しそうなので個人的に「むすんでひらいての法則」と命名(^^;.僕の考えでは,オブジェクト指向が先にきて次にOCPが来るのではなく,OCPがまずあってそれを実現するための手段としてオブジェクト指向がくると考えます.これとデザインパターンとの関連についての詳しい記事はこちらです.本当はOCPを広めるためにこの記事を書いたのですが,やはり雑誌の売れ行きを考えるとパターンをからめないといけなかったのです(苦笑).

The Liskov Substitution Principle (LSP)

Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

LSPは継承使う場合常に意識した方がよい重要な原則です.これを知らずして継承を使うべからず,といったところでしょう.なぜオブジェクト指向の入門書にこいつを書かないのかいまだに不思議です.LSPはMeyer先生のDesign by Contractでもうちょっと厳密に表せます.

The Dependency Inversion Principle (DIP)

A. High level modules should not depend upon low level modules. Both should depend upon abstractions.
B. Abstractions should not depend upon details. Details should depend upon abstractions.

オブジェクト指向では構造化プログラミングに対して依存関係が逆転してしまう,という法則です.オブジェクト指向で一番面白いところですね.今はどうか知りませんが,昔はCでごりごりプログラムを書いてきた人ほどオブジェクト指向に移行するのが難しいといわれました.その原因がこの逆転の発想なんでしょう.このことを踏まえて「依存関係のコペルニクス的転回」と勝手に命名したこともあります(笑).

The Interface Segregation Principle (ISP)

Clients should not be forced to depend upon interfaces that they do not use.

インターフェイスを分離せよ,インターフェイスを太らせてはいけない,ということです.静的型づけ言語の場合,これを実現するには Java の interface か C++ の多重継承がどうしても必要になります.意図は違いますが,Adapterパターンに似ていますね.Adapterパターンの場合は,他のオブジェクトとお話ができるようにインターフェイスを変換しよう,ということですが,この法則が言っているのは,お話するのに必要最小限のインターフェイスしか教えないようにしよう,ということです.

The Reuse/Release Equivalence Principle (REP)

The granule of reuse is the granule of release. Only components that are released through a tracking system can be effectively reused. This granule is the package.

ここからは,個々のクラスではなく,クラスを集めたパッケージに関する原則になります.この REP は,パッケージを再利用可能にするためのシステムについて述べたものです.一般に,クラス単体は再利用可能ではありません.あるクラスは他のクラスに依存している場合がほとんどです.再利用可能にするには,クラス群をリリースする単位としてパッケージ化し,バージョン管理を行うようにすべきだ,ということです.そういうシステムがない限り,再利用はうまくいかない,ということでしょう.

The Common Reuse Principle (CRP)

The classes in a package are reused together. If you reuse one of the classes in a package, you reuse them all.

パッケージに入れるクラスは何にするかという判定基準を再利用の観点から表したものです.あるパッケージをバージョンアップする場合,利用している側のソフトウェアにとって関係のないクラスが修正されたにも関わらず更新しなければならない,というのはおかしな話です.パッケージをリリースしたあとの配布の問題を考えてもこうなっていることが理想です.Interface Segregation Principle のパッケージ版といえますね.

The Common Closure Principle (CCP)

The classes in a package should be closed together against the same kinds of changes. a change that affects a package affects all the classes in that package.

今度は,パッケージに入れるクラスは何にするかという判定基準をメンテナンス性から表したものです.ソフトウェアを修正しなければならない場合,その修正があるパッケージの中で閉じているにこしたことはありません.だから,将来起こるであろう変更を想定した場合,いっしょに修正することになるクラスは同じパッケージに入れてしまったほうがよい,ということです.

The Acyclic Dependencies Principle (ADP)

The dependency structure between packages must be a directed acyclic graph (DAG). That is, there must be no cycles in the dependency structure.

ここから先は,パッケージ間の依存関係についての原則になります.ADP は,依存関係が循環してはいけない,ということを述べています.パッケージの依存関係がどこかで循環していると,それらのパッケージを単独でアップデートすることはできません.アップデートするとしたら,循環しているパッケージ全体を一度に行わなければならないのです.この原則は,必ず守らなければならないものといってよいでしょう.

The Stable Dependencies Principle (SDP)

The dependencies between packages in a design should be in the direction of the stability of the packages. A package should only depend upon packages that are more stable that it is.

ここではStability(安定性)という用語が出てきます.Robert C. Martinのいう安定性とは,「変更する難易度」とでもいうべきものです.安定しているパッケージは修正が難しく,不安定なパッケージは修正が容易,ということですね(なんか変な感じ).SDP は,パッケージの依存関係はより安定しているパッケージへと向かうべき,ということです.

The Stable Abstractions Principle (SAP)

Packages that are maximally stable should be maximally abstract. Instable packages should be concrete. The abstraction of a package should be in proportion to its stability.

今度はStabilityとAbstractionの関係です.パッケージの依存関係は抽象度が高いパッケージへの向かうべき,でしょうか.SAP と SDP は Dependency Inversion Principleのパッケージ版です.Robert C. Martin は,パッケージからこの安定性と抽象度を数値的に測定し,Main Sequence というアイデアを導入しています.このMain Sequenceの考え方にはとても感動しました.ぜひ彼の本または記事を読みましょう.

プログラミングスタイル

The Law of Demeter(デメテルの法則)

A method "M" of an object "O" should invoke only the the methods of the following kinds of objects:

  1. itself
  2. its parameters
  3. any objects it creates/instantiates
  4. its direct component objects

デメテルの法則の定義は,Brad Appletonの記事("Introducing Demeter and its Laws")から引用しました.オブジェクトは直接の友達以外お話しちゃだめ,というルール.友達の友達にまでアクセスすると,友達が勝手にそいつと縁を切った場合困る,ということでしょうね.このルールに厳密に従うにはラッパーを作らないといけないのでかなり面倒だと思います^^;.ほどほどがいいんじゃないでしょうか.

(著 石井勝)
(編集・転載 平鍋)

編集者追記:関連する記事