Skip to content

Instantly share code, notes, and snippets.

@culage
Last active December 30, 2015 08:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save culage/7805802 to your computer and use it in GitHub Desktop.
Save culage/7805802 to your computer and use it in GitHub Desktop.

開放/閉鎖原則 Open-Cloased Principle

[2013-12-05]

http://www.os.cis.iwate-u.ac.jp/wikky/wikky.cgi?%E3%82%AA%E3%83%BC%E3%83%97%E3%83%B3%E3%83%BB%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%BA%E3%83%89%E3%81%AE%E5%8E%9F%E5%89%87%28OCP%29

OCP原則の定義

オブジェクト指向設計における原則のひとつ。

ソフトウェアの構成要素は、拡張に対して開いていて、修正に対して閉じていなければならないという原則。

(この定義を理解しようとする必要はない。意味が分からなくて当然だ)

もっと具体的に書くと

ある種類の変更がかかったとき、
モジュールやクラス単位について、
1行たりともコードを変更せずに、新しい動きをさせることができなければならないという原則。
( 1行たりともコードを変更しない、という部分が「修正に対して閉じている」にあたる )
( 新しい動きをさせることができる、という部分が「拡張に対して開いている」にあたる )

OCP原則は「変更の種類 × モジュールやクラス単位」ごとに満たされているかどうかが決まるものである。

コードで書くと

class Shape
	draw:-> console.log "draw #{@shapeName}!"

class Circle extends Shape
	constructor:-> @shapeName = "circle";

class Square extends Shape
	constructor:-> @shapeName = "square";

class ShapeDrawer
	draw:(shapeList)->
		for shape in shapeList
			shape.draw()

main =->
	drawer = new ShapeDrawer()
	drawer.draw [new Circle(), new Square()]

main()

このコードは、新たに

class Triangle extends Shape
	constructor:-> @shapeName = "triangle";

を追加して、mainを

main =->
	drawer = new ShapeDrawer()
	drawer.draw [new Circle(), new Square(), new Triangle()]

と変更しても ShapeDrawer には1行たりともコード変更をしなくてよい。 そして、ShapeDrawer は "draw triangle!" という文字を出力するという新しい動きをさせることが出来るようになっている。

このとき、「Shapeを継承したクラスが増えるという変更種類」に対して「ShapeDrawerクラス」はOCP原則を満たしていると言える。

この原則って、どうやって使うの

原則の定義に「~なければならない」と書いてあるが、 上のコードを見てわかるようにOCP原則を、全ての変更種類、全てのモジュールやクラスについて満たすことは不可能である。

OCP原則はどこに対してそれを満たすかを選択するための概念であって、できるだけ多くにその原則を適用すること目的としたものではない

例えば、上のコード例だと図形がいろいろ追加されるのであれば、 「Shapeを継承したクラスが増えるという変更種類」に対してOCP原則を満たしていることはメリットになる。

しかし、「Shapeを継承したクラスが増えるという変更種類」がほとんど無く、 代わりにデコレーションの種類(例えば、"《circle》"だとか"{{circle}}"みたいな出力をしたい)がいろいろ追加されるのであれば、 「Shapeを継承したクラスが増えるという変更種類」に対してOCP原則を満たしていることは、全くメリットにならない。 それどころか、無駄に設計の複雑性を上げてしまい他の変更を行う妨げになってしまうという意味で、デメリットになる。

OCP原則を適用する箇所は、設計者が適切に決めなければならない。

まとめ

この原則が本当に言いたいことは、
「頻繁に修正がかかる変更種類」「それを抽象的に扱ったほうが、単純になるクラス」に対して
OCP原則を満たすように設計するべきである、ということである。

重要な箇所の引用

http://www.os.cis.iwate-u.ac.jp/wikky/wikky.cgi?%E3%82%AA%E3%83%BC%E3%83%97%E3%83%B3%E3%83%BB%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%BA%E3%83%89%E3%81%AE%E5%8E%9F%E5%89%87%28OCP%29

オープン・クローズドの原則(OCP)はオブジェクト指向設計の核心である。 この原則に適切に従うことで、オブジェクト指向技術から得られる利益(柔軟性、再利用性、保守性)を享受できる。

オブジェクト指向のプログラミング言語を使えば自動的にOCPに準拠できるわけではない。 また、アプリケーションのあらゆる部分で抽象を無闇に使えばいいわけでもない。(無駄なコストを支払う必要が発生する) 最も頻繁に変更されるプログラム部分にだけに的を絞って、抽象を適用するように努めるべきである。

つまり、早まった「抽象」をしないことも、「抽象」を使うのと同等に重要。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment