copyright(c) 2013 kuwata-lab.com all rights reserved.
委譲
機能の一部 or 全部を、他のオブジェクトに任せ
ること(丸投げ!)
class Foo {
private $m1;
function __constructor() {
$this->other = new OtherObj();
}
function hello(arg) {
$this->other->hello(arg);
}
.... 丸投げ!
copyright(c) 2013 kuwata-lab.com all rights reserved.
委譲と継承はよく似ている
## 継承は、メソッド探索を自動で行ってくれる
$this->isa->methodtbl->hello(...);
## 委譲は、メソッド探索を自力で行っている
$this->other->hello(...);
◆
◆
委譲は、「継承の自力版」と見なせる
言語サポートはないかわりに、複数の移譲先が可能、変更も可能
継承は、「委譲の限定版」と見なせる
移譲先は1つだけで変更も不可だが、言語サポートがあるので便利
(注)独自の見解です
copyright(c) 2013 kuwata-lab.com all rights reserved.
プロトタイプチェーン
## 委譲と同様に、探索先を自分で設定可能
this.__proto__ = new Foo();
## 継承と同様に、自動的に探索してくれる
$this.hello();
$this.__proto__.hello();
$this.__proto__.__proto__.hello();
◆ プロトタイプチェーンは、委譲と継承の間の子
委譲の柔軟性と、継承の利便性を合わせ持つ
(注)独自の見解です
copyright(c) 2013 kuwata-lab.com all rights reserved.
継承では $this が変わらない
1: class Foo {
2: function hello() { ... }
3: function main() {
4: ...; $this->hello(); ...;
5: }
6: }
7: class Bar extends Foo {
8: function hello() {...} // override
9: // main() はそのまま
10: }
11: $obj = new Bar();
12: $obj->main();
$this は Bar オブ
ジェクトのまま!
オーバーライドした
Bar#hello() が最終的に
呼び出される
難しい話なので、分から
なければ読み飛ばして!
copyright(c) 2013 kuwata-lab.com all rights reserved.
委譲では $this が変わる
1: class Foo {
2: function hello() { ... }
3: function main() {
4: ...; $this->hello(); ...; }
5: }
6: class Bar extends Foo {
7: function hello() { ... }
8: function main() {
9: $this->foo->main(); }
10: }
11: $obj = new Bar();
12: $obj->foo = new Foo();
13: $obj->main();
この $this は
Bar ではない!
せっかく Bar#hello() を
新しく定義したのに
呼び出されない!
(Decorator patternでありがち)
Foo オブジェクト
が $this になる!
難しい話なので、分から
なければ読み飛ばして!
copyright(c) 2013 kuwata-lab.com all rights reserved.
対策: $this を引数として渡す
class Foo {
function hello() { ... }
function main($_this=null) {
if ($_this === null) $_this = $this;
...; $_this->hello(); ...;
}
}
class Bar {
var $foo = new Foo();
function hello() { ... }
function main() {
$this->foo->main($this); } }
こんな面倒なことを
全メソッドで行うの?
この用意をしてないクラス
は委譲先にできないの?
難しい話なので、分から
なければ読み飛ばして!
copyright(c) 2013 kuwata-lab.com all rights reserved.
プロトタイプチェーンでは this が変わらない
1: function Foo() {}
2: Foo.prototype.hello = function() {...};
3: Foo.prototype.main = function() {
4: ...; this.hello(); ...;
5: };
6:
7: function Bar() {}
8: Bar.prototype.hello = function() {...};
9:
10: var obj = new Bar();
11: obj.__proto__ = new Foo();
12: obj.main();
この this は Bar オ
ブジェクトのまま!
委譲と同じことしてるのに、
Bar#hello() が呼ばれる!
(Decorator pattern大勝利の気配!)
copyright(c) 2013 kuwata-lab.com all rights reserved.
間違ったクラス設計例
class 受注先 {
var $name;
var $addr;
function 納期回答();
}
class 発注先 {
var $name;
var $addr;
function 納期問合わせ();
}
「受注先かつ発注先」なら両方に登録が必要◆
実体は同じなのに一元管理されないため、名寄せが必要
自称DB設計上級者に
ありがちな間違い
copyright(c) 2013 kuwata-lab.com all rights reserved.
間違ったクラス設計例
class 取引先 {
var $name;
var $addr;
}
class 受注先 extends 取引先 {
function 納期回答();
}
class 発注先 extends 取引先 {
function 納期問合わせ();
}
class 受発注先 extends 受注先,発注先 { }
「受注先が発注先にJob Change!」を表せない◆
一度作ったオブジェクトのクラスは変更できないせい
自称Java上級者に
ありがちな間違い
ダイヤモンド継承!
copyright(c) 2013 kuwata-lab.com all rights reserved.
好ましいクラス設計例
class 取引先 { // Player
var $name;
var $addr;
var $受注先 = new 受注先();
var $発注先 = new 発注先();
}
class 受注先 { // Role
function 納期回答(); }
class 発注先 { // Role
function 納期問合わせ(); }
「Player」と「Role」とを分け、委譲を使う◆
「受注先かつ発注先」も「Job Change!」も自然に表現可能
でも、受注先や発注
先って、対応する取
引先オブジェクトが
必要だよね?
copyright(c) 2013 kuwata-lab.com all rights reserved.
より好ましいクラス設計例
class 取引先 { ... }
class Role {
var $player;
function __constructor($player) {
$this->player = $player;
}
}
class 受注先 extends Role { ... }
class 発注先 extends Role { ... }
「Role」が「Player」を保持する(さっきと逆)◆
Role には Player が必要だが、Player には Role は必須ではない
Role が Player を保持
(なぜなら Role には Player が必要だから)
copyright(c) 2013 kuwata-lab.com all rights reserved.
若干の問題点
// 受注先である取引先
$player = new 取引先('○ 商会');
$role = new 受注先($player);
// 受注先として扱う
echo $role->納期回答();
// 取引先として扱う
echo $role->player->name;
echo $player->name;
Role と Player で使い方に差がある◆
Player の属性やメソッドに Role からアクセスするとき
Role からは、Player の属性へ
直接にはアクセスできない
copyright(c) 2013 kuwata-lab.com all rights reserved.
そこでプロトタイプベース!
class 取引先 { ... }
class Role {
function __constructor($player) {
$this->player = $player;
$this->__proto__ = $player;
}
}
class 受注先 extends Role { ... }
class 発注先 extends Role { ... }
Role をあたかも Player のように扱える◆
Decorator Pattern も DCI もいらんかったんや!
仮に PHP でこれが
可能だとすると…
copyright(c) 2013 kuwata-lab.com all rights reserved.
そこでプロトタイプベース!
// 受注先 (Role) の役割をもった取引先 (Player) は、
$player = new 取引先('○ 商会');
$role = new 受注先($player);
// Role としても Player としても扱える
echo $role->納期回答();
echo $role->name;
// 複数の Role を重ねることさえ可能
$role = new 発注先($role); // 受注先兼発注先
Role をあたかも Player のように扱える◆
Decorator Pattern も DCI もいらんかったんや!
Role なのに、まるで
Player のように扱える!