行为型模式
责任链模式(Chain of Responsibility)
- 描述:使多个处理者对象有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。
- 优点:降低耦合度,增强给予请求的类和处理请求的类的灵活性。
JS示例
// 定义抽象处理者
class Handler {
constructor(successor = null) {
this.successor = successor;
}
setNext(successor) {
this.successor = successor;
return successor;
}
handle(request) {
if (this.successor) {
return this.successor.handle(request);
}
}
}
// 定义具体的处理者
class ConcreteHandler1 extends Handler {
handle(request) {
if (request >= 0 && request < 10) {
console.log(`ConcreteHandler1 handled request: ${request}`);
} else if (this.successor) {
this.successor.handle(request);
}
}
}
class ConcreteHandler2 extends Handler {
handle(request) {
if (request >= 10 && request < 20) {
console.log(`ConcreteHandler2 handled request: ${request}`);
} else if (this.successor) {
this.successor.handle(request);
}
}
}
// 创建处理者链
const handler1 = new ConcreteHandler1();
const handler2 = new ConcreteHandler2();
handler1.setNext(handler2);
// 发送请求
[8, 15, 25].forEach(request => {
handler1.handle(request);
});
在这个例子中,我们定义了两个具体的处理者 ConcreteHandler1 和 ConcreteHandler2,它们各自处理特定范围内的请求。请求被发送给 handler1,然后根据请求的值决定是否处理,或者将请求传递给下一个处理者 handler2。
PHP示例
下面是一个 PHP 的责任链模式示例,展示了如何处理用户发布的帖子审核流程,其中包含版主、管理员和治安部门三个级别的处理者。
// 首先,定义一个抽象的处理者类,这个类将包含处理请求的通用逻辑和设置下一个处理者的功能。
interface HandlerInterface {
public function setNext(HandlerInterface $handler): HandlerInterface;
public function handle(string $post): string;
}
abstract class AbstractHandler implements HandlerInterface {
protected $successor;
public function setNext(HandlerInterface $handler): HandlerInterface {
$this->successor = $handler;
return $handler;
}
public function handle(string $post): string {
if ($this->successor) {
return $this->successor->handle($post);
}
return "Post not handled.";
}
}
// 接下来,定义具体的处理者类,每个类都会覆盖 handle 方法来提供具体的处理逻辑。
class Moderator extends AbstractHandler {
public function handle(string $post): string {
if (strpos($post, 'spam') === false) {
return "Post approved by moderator.";
}
return parent::handle($post);
}
}
class Administrator extends AbstractHandler {
public function handle(string $post): string {
if (strpos($post, 'sensitive') === false) {
return "Post approved by administrator.";
}
return parent::handle($post);
}
}
class LawEnforcement extends AbstractHandler {
public function handle(string $post): string {
if (strpos($post, 'illegal') === false) {
return "Post approved by law enforcement.";
}
return "Post rejected due to illegal content.";
}
}
// 最后,创建处理者链并发送请求:
$moderator = new Moderator();
$administrator = new Administrator();
$lawnEnforcement = new LawEnforcement();
// 构建责任链
$moderator->setNext($administrator)->setNext($lawnEnforcement);
// 测试不同的帖子
$posts = [
"This is a normal post.",
"This post contains spam.",
"This post contains sensitive information.",
"This post is illegal."
];
foreach ($posts as $post) {
echo "Handling post: \"$post\"\n";
echo $moderator->handle($post) . "\n";
}
在这个示例中,Moderator、Administrator 和 LawEnforcement 分别负责检查帖子是否包含垃圾信息、敏感信息和非法内容。如果帖子通过了当前处理者的检查,它会继续传递给链中的下一个处理者。如果帖子包含处理者不能接受的内容,它将停止在当前处理者处并返回相应的拒绝信息。
应用场景
- 有多个对象可以处理一个请求,但是具体哪个对象处理该请求在运行时刻自动确定。
- 希望避免请求的发送者和接收者之间的耦合,让请求可以自由地在对象之间传递。
- 处理一个请求的算法应该可以动态配置。
这个模式的好处是,你可以轻松地添加、删除或重新排列处理者,而无需修改客户端代码。这使得系统更加灵活和可扩展。
命令模式(Command)
- 描述:将一个请求封装为一个对象,从而使你可用不同的请求把客户端参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
- 优点:请求发送者与请求接收者解耦,可以实现命令的撤销和重做。
JS示例
下面是一个使用 ES6 的命令模式示例,我们将创建一个简单的文本编辑器,其中包含一些基本的编辑命令,如插入、删除和撤销。
// 首先,定义一个命令接口:
class Command {
constructor(editor) {
this.editor = editor;
}
execute() {
throw new Error('Method not implemented.');
}
undo() {
throw new Error('Method not implemented.');
}
}
// 然后,定义具体的命令类:
class InsertCommand extends Command {
constructor(editor, text) {
super(editor);
this.text = text;
}
execute() {
this.editor.insert(this.text);
this.previousText = this.editor.getText();
}
undo() {
this.editor.setText(this.previousText);
}
}
class DeleteCommand extends Command {
constructor(editor, start, end) {
super(editor);
this.start = start;
this.end = end;
}
execute() {
this.removedText = this.editor.getText().slice(this.start, this.end);
this.editor.deleteText(this.start, this.end);
}
undo() {
this.editor.insertText(this.start, this.removedText);
}
}
// 接着,定义接收者(Editor):
class Editor {
constructor() {
this.text = '';
}
insert(text) {
this.text += text;
}
deleteText(start, end) {
this.text = this.text.slice(0, start) + this.text.slice(end);
}
insertText(position, text) {
this.text = this.text.slice(0, position) + text + this.text.slice(position);
}
getText() {
return this.text;
}
setText(text) {
this.text = text;
}
}
// 最后,创建一个调用者(Invoker),它将存储命令并执行它们:
class Invoker {
constructor() {
this.commands = [];
this.current = -1;
}
storeAndExecute(command) {
this.current++;
if (this.current < this.commands.length) {
this.commands.splice(this.current);
}
this.commands.push(command);
command.execute();
}
undo() {
if (this.current > -1) {
this.commands[this.current].undo();
this.current--;
}
}
}
// 现在,我们可以使用这些类来模拟编辑器的行为:
const editor = new Editor();
const invoker = new Invoker();
invoker.storeAndExecute(new InsertCommand(editor, 'Hello, '));
invoker.storeAndExecute(new InsertCommand(editor, 'world!'));
console.log(editor.getText()); // 输出: Hello, world!
invoker.undo();
console.log(editor.getText()); // 输出: Hello,
PHP示例
下面是一个简单的命令模式的 PHP 示例,我们将创建一个遥控器,它可以用来控制不同的电器设备,如灯和风扇,执行开和关的操作。
// 首先,定义命令接口:
interface Command {
public function execute();
public function undo();
}
// 接着,定义具体的命令类,这里以灯为例:
class LightOnCommand implements Command {
private $light;
public function __construct(Light $light) {
$this->light = $light;
}
public function execute() {
$this->light->turnOn();
}
public function undo() {
$this->light->turnOff();
}
}
class LightOffCommand implements Command {
private $light;
public function __construct(Light $light) {
$this->light = $light;
}
public function execute() {
$this->light->turnOff();
}
public function undo() {
$this->light->turnOn();
}
}
// 然后,定义接收者类,这里是灯:
class Light {
public function turnOn() {
echo "Light is on.\n";
}
public function turnOff() {
echo "Light is off.\n";
}
}
// 最后,创建一个调用者类,它将存储并执行命令:
class RemoteControl {
private $command;
public function setCommand(Command $command) {
$this->command = $command;
}
public function pressButton() {
$this->command->execute();
}
public function undo() {
$this->command->undo();
}
}
// 现在,我们可以使用这些类来模拟遥控器控制灯的行为:
$light = new Light();
$remote = new RemoteControl();
$lightOn = new LightOnCommand($light);
$lightOff = new LightOffCommand($light);
$remote->setCommand($lightOn);
$remote->pressButton(); // 输出: Light is on.
$remote->setCommand($lightOff);
$remote->pressButton(); // 输出: Lig