« アクティベーションオブジェクトによるメモリリーク | メイン | Progressionのパターン »

プロパティとはなにかを改めて考えてみる

通常、オブジェクトはメソッドとプロパティの固まりだと説明されます。
プロパティは属性で、メソッドは操作だと説明される事が多いですよね。

すごくシンプルでわかりやすいのですが、
ここに「暗黙のgetter/setter」が加わると、この説明では破綻するように思えます。
いわく、「プロパティ(暗黙のgetter/setter)ってめそっどじゃん!!プロパティ==メソッド??はぁ?」みたいな。
ここまで切れられた事ないですけど、つまずきやすいところではあると思います。

この辺の説明を人にする時、すっきりと説明できた事がなくずっともやもやしていたので
ちょっとまとめてみたいと思います。


「Method」「Property」「getter/setter」「暗黙のgetter/setter」それぞれの関係

まず、↓の図を見て下さい。
prop0.jpg

いわゆる広い意味での「getter/setter」は破線の部分です。
そして、Method全体を表す集合とProperty全体を表す集合があり、2つの集合が重なっている部分が「暗黙のgetter/setter」です。
Methodに注意を向けると、Methodはいわゆる広い意味での「getter/setter」とそうでない部分に分割できるのがわかります。
また、Property全体の集合はつねに広い意味での「getter/setter」であることがわかります。


広い意味での「getter/setter」の定義は以下の通りです。

getter
慣習としてgetHoge()を使用する
例:
SIngleton.getInstance()
Iterator.hasNext()
対象となるオブジェクトの情報を取得するインターフェイスの総称
setter
慣習としてsetHoge()を使用する
例:
Object.setPropertyIsEnumerable()
対象となるオブジェクトの情報を上書きするインターフェイスの総称

プロパティの定義

次に「property」の定義ですが、これがちょっとくせ者です。 自分の中でももやもやしていた部分です。 まず、↑の表からわかるとおりとおり、広い意味での「getter/setter」とはインターフェイスです。 (言語仕様上の、implementsされるinterfaceではなく、もっと広い意味でのインターフェイス) インターフェイスなので、必ず利用する側と利用される側がいます。 この利用する側と利用される側の視点によって、「property」の定義は異なります

以下の通りです。

利用する側 利用される側
getter
慣習としてgetHoge()を使用する
例:
SIngleton.getInstance()
Iterator.hasNext()
対象となるオブジェクトの情報を取得するインターフェイスの総称
setter
慣習としてsetHoge()を使用する
例:
Object. setPropertyIsEnumerable()
対象となるオブジェクトの情報を上書きするインターフェイスの総称
プロパティ
対象となるオブジェクトの公開されたインスタンス変数(に見える)
自身の公開しているインスタンス変数、または暗黙のgetter/setter


例を挙げます。
以下のような関係があるとします。

prop1.jpg


Catクラスはpropertyであるnameとageを持っています。
これは、Masterからみると、Catインスタンスの変数です。
Catクラスの実装はともかく、すくなくともMasterからはインスタンス変数にしか見えません


一方、Catクラスの実装は以下の通りです

class Cat
{
public var name : String;
private var _age : int;
/**
* 暗黙のgetter/setterであるage
*/
public function get age():int
{
return _age;
}
public function set age(value:int):void
{
//猫の寿命はがんばって25年
if (!isLifeSpan(value))
return;
_age = vlue;
}
public static function isLifeSpan(age:int):Boolean
{
return age <= 25
}
}

Masterから見るとCatはnameとageというpropertyを持っているように見えますが、
Catにとっては、その実体はそれぞれインスタンス変数と暗黙のgetter/setterです。

このように、propertyという言葉は、誰の視点で語っているかでその意味が異なります。
この非対称性が、propertyを理解する肝であり、propertyという言葉の定義の難しさだと思います。
なんでこんな混乱の元凶である、「暗黙のgetter/setter」などというものがあるのでしょうか?

たとえば、もし暗黙のgetter/setterという仕組みがなければ、
Masterは以下のようにしてCat.ageを変更しなければいけないでしょう。
ageプロパティに代入する前に寿命の範囲内かどうか調べるメソッドを呼び出しています。

var myCat:Cat = new Cat();
var myCatAge:int = 20;
if (Cat.isLifeSpan(myCatAge))
    myCat.age = myCatAge

しかし、ageを設定するのに寿命の範囲内かどうか調べるロジックは、本来Catの仕事であるべきです。
Masterがそれを意識するのはいいデザインとはいえません。
暗黙のgetter/setterを使えば以下のようになります。

var myCat:Cat = new Cat();
myCat.age = 20;

みてのとおり、Masterにとってageプロパティの書き換えがシンプルになっています。
MasterはCatのageというインスタンス変数にアクセスしているつもりですが、
Cat側では寿命の範囲内かどうか調べるロジックが動いています。
つまり、ageを設定するにあたって必要なロジックがMasterからは隠蔽されています

ようするに、暗黙のgetter/setterは、getter/setterを呼び出す際に必要なロジックを
利用者側から隠蔽するために使われる
と言っていいんだと思います。


言葉の定義をまとめると、以下のようになります。

利用する側 利用される側
getter
慣習としてgetHoge()を使用する
例:
SIngleton.getInstance()
Iterator.hasNext()
対象となるオブジェクトの情報を取得するインターフェイスの総称
setter
慣習としてsetHoge()を使用する
例:
Object. setPropertyIsEnumerable()
対象となるオブジェクトの情報を上書きするインターフェイスの総称
プロパティ
対象となるオブジェクトの公開されたインスタンス変数(に見える)
自身の公開しているインスタンス変数、または暗黙のgetter/setter
暗黙のgetter
プロパティに見える 自身の情報を提供するインターフェイス.
情報とはインスタンス変数かも知れないしそうではないかもしれない
暗黙のsetter
プロパティに見える 単なるインスタンス変数への代入以上の事を行う.

また、ActionScriptの流儀としては、getHoge()のような慣習的なgetter/setterは、プロパティを使用する事が多いようです。

× MovieClip.getX()
MovieClip.x

× MovieClip.setX(100)
MovieClip.x = 100

xプロパティが、MovieClipのインスタンス変数なのか、暗黙のgetter/setterかどうかは
利用者側からはわからないし、知る必要もありません。
ただxプロパティに値を代入すると何が起こるか知っていれさえすればいいのです。

まとめ

冒頭であげた、
「プロパティは属性で、メソッドは操作だと説明したのに、プロパティ(暗黙のgetter/setter)ってめそっどじゃん!!」
に対する答えは、
「実装の上ではその通り、でも概念の上ではプロパティ(暗黙のgetter/setter)は属性だよ」ということになると思います。

「実装の上では」というのは利用される側の視点、「概念の上」は利用する側の視点にそれぞれ対応します。
つまり、「プロパティは属性で、メソッドは操作」という物言いは、利用する側の視点(概念)を語っているのです。利用される側の視点(実装)ではありません

このように実装と概念という2層で常にプログラムを考えていく姿勢が、
オブジェクト指向を理解する鍵なんじゃないかなぁと最近は思っています。

トラックバック

このエントリーのトラックバックURL:
http://www.imajuk.com/mt4/mt-tb.cgi/38

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

About

2008年7月29日 23:29に投稿されたエントリーのページです。

ひとつ前の投稿は「アクティベーションオブジェクトによるメモリリーク」です。

次の投稿は「Progressionのパターン」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。