This is version . It is not the current version, and thus it cannot be edited.
[Back to current version]   [Restore this version]

責務でクラスは決まらない#

「責務」によってクラスが定義されるといくつかの解説書には書いてありますが、これは誤りだと私は考えています。誤りが言い過ぎだとしても、初学者に大きな誤解を与えています。
責務という言葉を言い換えると「しなければならないこと」「出来なければならないこと」となります。クラスを利用する側から見るとそのクラスが何を出来るか(してくれるか)は確かに重要です。
ですがそれはクラスを使う側から見た場合であって、設計する人はそれだけではクラスを定義出来ません。一つ例を出します。

「ジュース売り」という責務#

「ジュース売り」という責務を考えてみます。
ジュース売りがしなければならないことは次のような事です。
  1. 注文を聞く
  2. 金額を伝える
  3. お金をもらう
  4. 品物とお釣りを渡す
では、この責務を請け負えるモノは何が考えられるでしょうか?

ジュース売りを請け負えるモノ#

  • 人間
  • 自動販売機
ジュース売りを請け負えるモノとして少なくともこの2つが考えられます。将来的には「ロボット」も入ってくるかもしれません。
ジュースを買いたいという利用者側から見れば、それが人間だろうが自販機だろうが要件は満たされます。つまり責務が決まったからと言ってそのモノまでは決められないのです。
これは当然で、「何が出来るのか」というのは処理の規定であって、データ構造、つまりそのモノの状態は関係無いからです。
Javaなどでは「Interface」として定義するのが責務です。Interfaceはメソッドを規定するだけで中身は実装者任せです。まさに、「責務は決めるがモノは決めない」という機能です。ちなみに私はInterfaceのことを責務ではなく「役割」と呼ぶようにしています。

責務で考えると誤ったクラスが出てくる例#

従業員を考えてみます。業務システムを設計する際に「従業員クラス」というのは良く出て来ます。
employee.png

また、スポーツジムの管理システムを設計すると「ジムの会員クラス」もあります。
jymmember.png

これらをある1人の人の視点から見るとクラス図は次のようになります。 human.png

ですがよく考えてみるとこれらの中でモノと呼べるのは人間だけです。従業員やジムの会員は、その人がその時その時に負っている役割に過ぎません。責務と言い換えてもいいでしょう。会社の中で負っているのが従業員という役割、ジムに行けば会員という役割に変わりますが、実体としては同じ人です。
これを正しいクラス図にすると次になります。
human_interface.png

人事システムを設計する際に「ジムの会員」という役割を考慮する必要は現実にはないと思います。人事システムから見れば「人間=従業員」という構図は成り立つので、そのシステムで従業員をクラスとして定義することは正しいと思います。
しかしそれはシステム設計上の便宜性から来るものであることを忘れてはいけません。役割をクラスと勘違いした結果の上記のような誤った設計/実装を大変多く見かけます。

責務をもう少し掘り下げてみる#

責務というのは英語の'responsibility'の訳です。一般的には「責任」と訳します。
オブジェクト(またはクラス)が持つ責務として世間にある解説では、
  1. 業務に必要な処理のこと
  2. オブジェクトが持っている情報を通知すること
と書いてあります。
業務に必要な処理というのはジュース売りを例に取ると「注文を聞く」などがそれです。これはその通りそのクラスが負うべき責務です。
「オブジェクトが持っている情報を通知すること」は内部にデータ構造がないと不可能なので、データ構造に依存するかのような説明に見えます。しかし、情報を通知するということはどんなオブジェクトにも必要な処理であって特定の業務とは無関係です。これをオブジェクトの責務と呼ぶのは勘違いだと私は考えます。オブジェクト指向においてオブジェクトに与えられている機能と言うべきでしょう。
責務というのはそのクラスがシステムの中で果たすべき役割のことであって、仕組みとして備わっている機能のことを呼ぶべきではないと言うのが私の考えです。責務はやはり処理を規定するだけでデータ構造には依存しないのです。

単一責務の原則はおかしい#

1クラス1責務という原則が提唱されていますが、上記の人間クラスの例を考えてもこれはおかしいのではないかと考えています。
私が読んだサイトには次のように書いてあります。Single Responsibility Principle
This principle states that if we have 2 reasons to change for a class,
we have to split the functionality in two classes.
Each class will handle only one responsibility and on future if we need
to make one change we are going to make it in the class which handle it.
「クラスを変更する理由が2つある場合は機能を2つのクラスに分割すべき」というのが
この原則です。それぞれのクラスは1つだけの責任(責務)を負い、将来変更が必要になった
時にその責務を負うクラス内で変更を行います。
しかし上記で書いたように人間は複数の役割を負うことがあります。それと同じようにシステム設計の中で見つけたクラスが複数の役割を負うことはよくあることです。
ある役割が負うべき機能や処理が増えた場合、その役割(Interface)だけを変更した上で、役割を請け負っている実体つまりクラスを変更します。同じクラスが別の役割も負っている場合はその役割の変更に応じて再度修正すべきです。
例えば受注伝票と発注伝票というクラスを考える場合、それぞれが明細の一覧を持ちます。「明細の一覧を扱う」という業務的な役割です。この役割には、
  • 明細の合計金額を返す
  • 明細の件数を返す
などの処理が考えられます。
一方でこれらの伝票をRDBに保存したいような場合は、「RDBに読み書きする」というシステム的な役割も負います。
  • 伝票をRDBに書く
  • 伝票をRDBから読む
などが考えられます。
twointerface.png
責務という言葉の定義にデータ構造への依存性を含むのかによってここでの議論は変わってきますが、含まない立場の私からは誤りに見えます。

みんななぜ間違うのか?#

世間ではクラスと思われているものが実は誤りである。なぜそうなってしまうのでしょうか?
クラスを設計する際、その基となるのは顧客からの要求です。要件と呼ばれます。この要件は、「システムでxxxがしたい」「システムを使ってmmmが出来るようになりたい」という実務処理の記述です。つまりシステムの役割を列挙したものです。
役割というのは上で書いたように処理に過ぎません。クラスとして必要なデータ構造はそれだけでは出て来ません。
ですが、オブジェクト指向に不慣れな設計者・実装者はその要件(処理)だけを頼りに開発してしまいます。データ構造を考えずに処理だけを追いかけてしまうのです。これが誤りの根本です。

まとめ#

  • 役割(責務)をクラスにしてはいけない
  • 役割はInterfaceにする
  • 要件だけに着目してもクラスは見つけられない

何をクラスにするのか

添付ファイルの追加

ログイン済のユーザのみが添付ファイルをアップロード出来ます。

添付ファイル一覧

Kind Attachment Name Size Version Date Modified Author Change note
png
employee.png 0.7 kB 1 27-1-2011 22:46 ytp
png
human.png 3.7 kB 1 27-1-2011 22:46 ytp
png
human_interface.png 6.1 kB 3 12-2-2011 01:42 ytp
png
inherit_human.png 4.9 kB 2 20-2-2011 15:30 ytp
png
jymmember.png 0.8 kB 1 27-1-2011 22:46 ytp
png
twointerface.png 9.5 kB 3 28-1-2011 01:18 ytp
« This particular version was published on 28-1-2011 01:13 by ytp.