デザインパターンの勉強をしていたところ、
ストラテジーパターンは今なら無名関数で出来るよね~みたいな話を見かけ、
wikipediaを見ながら実装しようとしたら思いもよらないところでつまったのでメモ。
wikiに見るPythonのストラテジーパターン実装例
Python では関数が第一級オブジェクトであり、このパターンを明示的に定義する必要はない。
下記はコールバック関数を用いる GUI プログラミングで見られる例である。
class Button:
"""A very basic button widget."""
def __init__(self, submit_func, label):
self.on_submit = submit_func # strategy 関数を直接生成
self.label = label
# 異なる戦略を持つ二つのインスタンスを作成
button1 = Button(sum, "Add 'em")
button2 = Button(lambda nums: " ".join(map(str, nums)), "Join 'em")
# ボタンをテストする
numbers = range(1, 10) # A list of numbers 1 through 9
print button1.on_submit(numbers) # displays "45"
print button2.on_submit(numbers) # displays "1 2 3 4 5 6 7 8 9"
PHPで同様のものを実装してみる
class Button
{
public $submit;
public function __construct(callable $submit_func)
{
$this->submit = $submit_func;
}
}
$button1 = new Button('array_sum');
$button2 = new Button(function($nums) { return implode(' ', $nums); });
$nums = range(1, 9);
echo $button1->submit($nums);
echo $button2->submit($nums);
すると…
PHP Fatal error: Call to undefined method Button::submit() in ...
そんなメソッドないでしょと怒られる
呼び出し方が違うようなので探したところきちんと書いてあるところがありました。
それにそって正しく実装してみます。
PHPで正しく同様のものを実装してみる
class Button
{
public $submit;
public function __construct(callable $submit_func)
{
$this->submit = $submit_func;
}
}
$button1 = new Button('array_sum');
$button2 = new Button(function($nums) { return implode(' ', $nums); });
$nums = range(1, 9);
echo call_user_func($button1->submit, $nums);
echo call_user_func($button2->submit, $nums);
もしくは
$button1 = (new Button('array_sum'))->submit;
$button2 = (new Button(function($nums) { return implode(' ', $nums); }))->submit;
$nums = range(1, 9);
echo $button1($nums);
echo $button2($nums);
参考URL
[PHP] クラスにおけるメンバ変数(プロパティ)内の関数オブジェクトとメソッドの性質:無名関数(クロージャ)について
Strategy パターン