观察者模式 目的 观察者模式 为对象实现“发布/订阅”功能,每当“主题”状态改变的时候,将通知所有被绑定的“观察者”。观察者模式用于减少耦合的对象数量,使用松散耦合来代替。
使用场景
在 GUI 程序中,通过观察消息队列来显式作业执行进度
说明 PHP 中提供了两个可以帮助我们实现观察者模式的接口:SplObserver 和 SplSubject。
UML 类图
代码 User.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <?php declare (strict_types = 1 );namespace DesignPatterns \Behavioral \Observer ;use SplSubject ;use SplObjectStorage ;use SplObserver ;class User implements SplSubject { private string $email ; private SplObjectStorage $observers ; public function __construct ( ) { $this ->observers = new SplObjectStorage (); } public function attach (SplObserver $observer ) { $this ->observers->attach ($observer ); } public function detach (SplObserver $observer ) { $this ->observers->detach ($observer ); } public function changeEmail (string $email ) { $this ->email = $email ; $this ->notify (); } public function notify ( ) { foreach ($this ->observers as $observer ) { $observer ->update ($this ); } } }
UserObserver.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <?php declare (strict_types = 1 );namespace DesignPatterns \Behavioral \Observer ;use SplObserver ;use SplSubject ;class UserObserver implements SplObserver { private array $changedUsers = []; public function update (SplSubject $subject ) { $this ->changedUsers[] = clone $subject ; } public function getChangedUsers ( ): array { return $this ->changedUsers; } }
测试 Tests/ObserverTest.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php declare (strict_types = 1 );namespace DesignPatterns \Behavioral \Observer \Tests ;use DesignPatterns \Behavioral \Observer \User ;use DesignPatterns \Behavioral \Observer \UserObserver ;use PHPUnit \Framework \TestCase ;class ObserverTest extends TestCase { public function testChangeInUserLeadsToUserObserverBeingNotified ( ) { $observer = new UserObserver (); $user = new User (); $user ->attach ($observer ); $user ->changeEmail ('foo@bar.com' ); $this ->assertCount (1 , $observer ->getChangedUsers ()); } }