设计模式之观察者模式的原理和实现方法
7天成为Magento系统架构师,现在开始学习Magento全栈开发!
《Magento2.X企业级开发实战》
观察者模式
是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个“观察”该对象的其他对象。
代码示例
<?php
/**
* Observer Design Pattern
*
* Intent: Lets you define a subscription mechanism to notify multiple objects
* about any events that happen to the object they're observing.
*
* Example: In this example the Observer pattern allows various objects to
* observe events that are happening inside a user repository of an app.
*
* The repository emits various types of events and allows observers to listen
* to all of them, as well as only individual ones.
*/
/**
* The UserRepository represents a Subject. Various objects are interested in
* tracking its internal state, whether it's adding a new user or removing one.
*/
class UserRepository implements \SplSubject
{
/**
* @var array The list of users.
*/
private $users = [];
// Here goes the actual Observer management infrastructure. Note that it's
// not everything that our class is responsible for. Its primary business
// logic is listed below these methods.
/**
* @var array
*/
private $observers = [];
public function __construct()
{
// A special event group for observers that want to listen to all
// events.
$this->observers["*"] = [];
}
private function initEventGroup(string $event = "*"): void
{
if (!isset($this->observers[$event])) {
$this->observers[$event] = [];
}
}
private function getEventObservers(string $event = "*"): array
{
$this->initEventGroup($event);
$group = $this->observers[$event];
$all = $this->observers["*"];
return array_merge($group, $all);
}
public function attach(\SplObserver $observer, string $event = "*"): void
{
$this->initEventGroup($event);
$this->observers[$event][] = $observer;
}
public function detach(\SplObserver $observer, string $event = "*"): void
{
foreach ($this->getEventObservers($event) as $key => $s) {
if ($s === $observer) {
unset($this->observers[$event][$key]);
}
}
}
public function notify(string $event = "*", $data = null): void
{
echo "UserRepository: Broadcasting the '$event' event.\n";
foreach ($this->getEventObservers($event) as $observer) {
$observer->update($this, $event, $data);
}
}
// Here are the methods representing the business logic of the class.
public function initialize($filename): void
{
echo "UserRepository: Loading user records from a file.\n";
// ...
$this->notify("users:init", $filename);
}
public function createUser(array $data): User
{
echo "UserRepository: Creating a user.\n";
$user = new User();
$user->update($data);
$id = bin2hex(openssl_random_pseudo_bytes(16));
$user->update(["id" => $id]);
$this->users[$id] = $user;
$this->notify("users:created", $user);
return $user;
}
public function updateUser(User $user, array $data): User
{
echo "UserRepository: Updating a user.\n";
$id = $user->attributes["id"];
if (!isset($this->users[$id])) {
return null;
}
$user = $this->users[$id];
$user->update($data);
$this->notify("users:updated", $user);
return $user;
}
public function deleteUser(User $user): void
{
echo "UserRepository: Deleting a user.\n";
$id = $user->attributes["id"];
if (!isset($this->users[$id])) {
return;
}
unset($this->users[$id]);
$this->notify("users:deleted", $user);
}
}
/**
* Let's keep the User class trivial since it's not the focus of our example.
*/
class User
{
public $attributes = [];
public function update($data): void
{
$this->attributes = array_merge($this->attributes, $data);
}
}
/**
* This Concrete Component logs any events it's subscribed to.
*/
class Logger implements \SplObserver
{
private $filename;
public function __construct($filename)
{
$this->filename = $filename;
if (file_exists($this->filename)) {
unlink($this->filename);
}
}
public function update(\SplSubject $repository, string $event = null, $data = null): void
{
$entry = date("Y-m-d H:i:s") . ": '$event' with data '" . json_encode($data) . "'\n";
file_put_contents($this->filename, $entry, FILE_APPEND);
echo "Logger: I've written '$event' entry to the log.\n";
}
}
/**
* This Concrete Component sends initial instructions to new users. The client
* is responsible for attaching this component to a proper user creation event.
*/
class OnboardingNotification implements \SplObserver
{
private $adminEmail;
public function __construct($adminEmail)
{
$this->adminEmail = $adminEmail;
}
public function update(\SplSubject $repository, string $event = null, $data = null): void
{
// mail($this->adminEmail,
// "Onboarding required",
// "We have a new user. Here's his info: " .json_encode($data));
echo "OnboardingNotification: The notification has been emailed!\n";
}
}
/**
* The client code.
*/
$repository = new UserRepository();
$repository->attach(new Logger(__DIR__ . "/log.txt"), "*");
$repository->attach(new OnboardingNotification("1@example.com"), "users:created");
$repository->initialize(__DIR__ . "/users.csv");
// ...
$user = $repository->createUser([
"name" => "John Smith",
"email" => "john99@example.com",
]);
// ...
$repository->deleteUser($user);
如无特殊说明或标注,任何个人或组织,复制、转载、采集本站内容请注明:
本文来源于:【Magento中文网】,并添加本文地址链接。
如未按上述操作复制或转载,本站有权追究法律责任。
若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
本文来源于:【Magento中文网】,并添加本文地址链接。
如未按上述操作复制或转载,本站有权追究法律责任。
若本站内容侵犯了原著者的合法权益,可联系我们进行处理。