オブジェクト指向を用いた設計を考えて調べものをしていた時に**Primitive-obsession(基本データ型への執着)**という言葉を知ったので自分なりにまとめておきました。
Primitive-obsessionとは
「Primitive-obsession(基本データ型への執着)」とは、ドメインの概念を表すのに基本データ型を用いることを言います。
たとえば、メッセージを表すのに文字列を使う、金額を表すのに整数を使う、なんらかのオブジェクトを表すのに構造体・ディクショナリ・ハッシュを使うといったものです。
なにが良くないのか?
たとえば電話番号を表すのに文字列や数値を使っていた場合、電話番号特有の処理などを書きたい場合(-を抜いた数値型に変換したり、その逆をしたりする処理)、そのオブジェクト自体のメソッドとして記述できないので処理用の関数がバラバラに置かれることになります。
そうなるとメンテナンス性が下がるし、変更にも弱くなりやすいです。
そういう時にはPhoneNumberというクラスを作って、PhoneNumberのインスタンスを使うという設計にした方が電話番号に関する処理がカプセル化して良い設計になります。
コード例
名前と電話番号を持っているUserクラスを元にPrimitive-obsessionになっている例とそれを改善した例を示しながら説明します。
まず以下のPrimitive-obsessionになっているUserクラスをみて下さい。
# Primitive-obsessionになっているUserクラス
class User
def name
self.name
end
#
# nameにユーザーの名前に文字列を代入する
#
def name=(string)
self.name = string
end
def phone_number
self.phone_number
end
#
# phone_numberに電話番号を表す数値を代入する
#
def phone_number=(integer)
self.phone_number = integer
end
end
一見問題ないように見えますが、要件が増えてくると複雑になっていきます。
例えば、ユーザーの名前を苗字(lastname)と名前(firstname)で分けて管理したい、電話番号をハイフン付きで表示したい、などの要件が出てきたとき、それらの処理を行うメソッドをすべてUserクラス内に記述しないといけません。
そうすると、Userクラスが電話番号と名前という複数の責任を負わないといけないため、オブジェクト指向の原則である単一責任の原則から外れてしまい、すぐにクラスが肥大化してしまいます。
では、今度はPrimitive-obsessionを改善した例を以下に示します。
#
# Primitive-obsessionを改善したUserクラス
#
# User.nameはUserNameクラスのインスタンスになっている
# User.phone_numberはPhoneNumberクラスのインスタンスになっている
#
class User
def name
self.name =|| new UserName()
end
def name=(user_name)
self.name = user_name
end
def phone_number
self.name =|| new Telephone()
end
def phone_number=(phone_number)
self.telephone = telephone
end
end
#
# ユーザー名を管理するクラス
#
class UserName
def initialize(first_name=null, last_name=null)
self.first_name = first_name
self.last_name = last_name
end
def first_name
self.first_name
end
def first_name=(string)
self.first_name = string
end
def last_name
self.last_name
end
def last_name=(string)
self.last_name = string
end
end
#
# 電話番号を管理するクラス
#
class PhoneNumber
def initialize(integer)
self.number = integer
end
def number
self.number
end
def number=(integer)
self.number = integer
end
end
前回と違い、電話番号はPhoneNumberクラス、ユーザーの名前はUserNameクラスで表現するように変更しました。
これにより、ユーザーの名前に関する責任はUserNameクラス、電話番号に関する責任はPhoneNumberクラスに分割することが出来ました。
このような設計を行うことで、Userクラスが負っていた複数の責任を分割してクラスを小さく出来るだけでなく、例えば求人サイトなどの企業を表すCompanyクラスなどが出来た場合にはPhoneNumberクラスを使いまわす事ができます。
終わりに
いままではフレームワークの流儀に合わせたクラス設計(MVC)ぐらいしかしてこなかったのであまりオブジェクト指向を強く意識したことがなかったですが、勉強するとなかなか発見が多くて結構面白いです。
自分はいまRubyでプログラムを書くことが多いので、これを気にちゃんとオブジェクト指向の書き方を勉強し直したいと思います。