Vì vậy, hãy nói rằng bạn không muốn mẫu Observer bởi vì nó đòi hỏi bạn phải thay đổi phương pháp lớp học của bạn để xử lý các nhiệm vụ lắng nghe, và muốn một cái gì đó chung chung. Và giả sử bạn không muốn sử dụng thừa kế extends
vì bạn có thể đã kế thừa trong lớp của mình từ một số lớp khác. Nó sẽ không tuyệt vời khi có một cách chung chung để làm cho bất kỳ lớp học nào có thể cắm bất kỳ nỗ lực nào mà không cần nỗ lực nhiều? Dưới đây là cách thực hiện:
<?php
////////////////////
// PART 1
////////////////////
class Plugin {
private $_RefObject;
private $_Class = '';
public function __construct(&$RefObject) {
$this->_Class = get_class(&$RefObject);
$this->_RefObject = $RefObject;
}
public function __set($sProperty,$mixed) {
$sPlugin = $this->_Class . '_' . $sProperty . '_setEvent';
if (is_callable($sPlugin)) {
$mixed = call_user_func_array($sPlugin, $mixed);
}
$this->_RefObject->$sProperty = $mixed;
}
public function __get($sProperty) {
$asItems = (array) $this->_RefObject;
$mixed = $asItems[$sProperty];
$sPlugin = $this->_Class . '_' . $sProperty . '_getEvent';
if (is_callable($sPlugin)) {
$mixed = call_user_func_array($sPlugin, $mixed);
}
return $mixed;
}
public function __call($sMethod,$mixed) {
$sPlugin = $this->_Class . '_' . $sMethod . '_beforeEvent';
if (is_callable($sPlugin)) {
$mixed = call_user_func_array($sPlugin, $mixed);
}
if ($mixed != 'BLOCK_EVENT') {
call_user_func_array(array(&$this->_RefObject, $sMethod), $mixed);
$sPlugin = $this->_Class . '_' . $sMethod . '_afterEvent';
if (is_callable($sPlugin)) {
call_user_func_array($sPlugin, $mixed);
}
}
}
} //end class Plugin
class Pluggable extends Plugin {
} //end class Pluggable
////////////////////
// PART 2
////////////////////
class Dog {
public $Name = '';
public function bark(&$sHow) {
echo "$sHow<br />\n";
}
public function sayName() {
echo "<br />\nMy Name is: " . $this->Name . "<br />\n";
}
} //end class Dog
$Dog = new Dog();
////////////////////
// PART 3
////////////////////
$PDog = new Pluggable($Dog);
function Dog_bark_beforeEvent(&$mixed) {
$mixed = 'Woof'; // Override saying 'meow' with 'Woof'
//$mixed = 'BLOCK_EVENT'; // if you want to block the event
return $mixed;
}
function Dog_bark_afterEvent(&$mixed) {
echo $mixed; // show the override
}
function Dog_Name_setEvent(&$mixed) {
$mixed = 'Coco'; // override 'Fido' with 'Coco'
return $mixed;
}
function Dog_Name_getEvent(&$mixed) {
$mixed = 'Different'; // override 'Coco' with 'Different'
return $mixed;
}
////////////////////
// PART 4
////////////////////
$PDog->Name = 'Fido';
$PDog->Bark('meow');
$PDog->SayName();
echo 'My New Name is: ' . $PDog->Name;
Trong phần 1, đó là những gì bạn có thể bao gồm với lời gọi require_once()
ở đầu tập lệnh PHP của bạn. Nó tải các lớp để làm một cái gì đó có thể cắm được.
Trong phần 2, đó là nơi chúng tôi tải lớp học. Lưu ý Tôi không phải làm bất cứ điều gì đặc biệt cho lớp, điều này khác biệt đáng kể so với mẫu Observer.
Trong phần 3, đó là nơi chúng tôi chuyển lớp của chúng tôi thành "có thể cắm" (nghĩa là, hỗ trợ các plugin cho phép chúng tôi ghi đè lên các phương thức và thuộc tính lớp). Vì vậy, ví dụ, nếu bạn có một ứng dụng web, bạn có thể có một đăng ký plugin, và bạn có thể kích hoạt các plugin ở đây. Cũng thông báo chức năng Dog_bark_beforeEvent()
. Nếu tôi đặt $mixed = 'BLOCK_EVENT'
trước câu lệnh trả về, nó sẽ chặn con chó khỏi sủa và cũng sẽ chặn Dog_bark_afterEvent vì sẽ không có bất kỳ sự kiện nào.
Trong phần 4, đó là mã hoạt động bình thường, nhưng lưu ý rằng những gì bạn có thể nghĩ sẽ chạy không chạy như thế chút nào. Ví dụ, con chó không công bố tên của nó là 'Fido', nhưng 'Coco'. Con chó không nói 'meow', nhưng 'Woof'. Và khi bạn muốn nhìn vào tên của con chó sau đó, bạn thấy nó là 'Khác biệt' thay vì 'Coco'. Tất cả những ghi đè đó được cung cấp trong Phần 3.
Vậy cách thức hoạt động của tính năng này? Vâng, hãy loại trừ eval()
(mà mọi người nói là "ác") và loại trừ rằng đó không phải là mẫu Observer. Vì vậy, cách nó hoạt động là lớp trống lén lút được gọi là Pluggable, không chứa các phương thức và thuộc tính được sử dụng bởi lớp Dog. Vì vậy, vì điều đó xảy ra, các phương pháp ma thuật sẽ thu hút chúng tôi. Đó là lý do tại sao trong phần 3 và 4 chúng ta gây rối với đối tượng bắt nguồn từ lớp Pluggable, không phải chính lớp Dog.Thay vào đó, chúng ta để cho lớp Plugin làm "chạm" trên đối tượng Dog cho chúng ta. (Nếu đó là một số kiểu thiết kế mà tôi không biết - hãy cho tôi biết.)
Lưu ý rằng đối với PHP> = 5.0, bạn có thể thực hiện điều này bằng cách sử dụng giao diện Quan sát/Chủ đề được xác định trong SPL: http://www.php.net/manual/en/class.splobserver.php –
Lưu ý về lưu ý: đây không phải là ví dụ về mẫu Observer. Đó là một ví dụ về [Mô hình hòa giải '] (http://sourcemaking.com/design_patterns/mediator). Các nhà quan sát thực sự hoàn toàn là thông báo, không có thông báo đi qua hoặc thông báo có điều kiện (cũng không có một người quản lý trung tâm để kiểm soát các thông báo). Nó không làm cho câu trả lời * sai *, nhưng cần lưu ý để ngăn mọi người gọi nhầm tên bằng tên sai ... – ircmaxell
Lưu ý rằng khi sử dụng nhiều móc/trình nghe, bạn chỉ nên trả về chuỗi hoặc mảng, không phải cả hai. Tôi đã thực hiện một cái gì đó tương tự cho Hound CMS - https://getbutterfly.com/hound/. – Ciprian