查看here和here报告的命令模式的UML图,调用者对象的类(调用命令对象的
execute()
方法的类)必须提供一个setCommand()
方法允许客户端代码在调用者上设置正确的命令对象:但是在处理具有“不同参数”的命令对象时如何使用这种方法,而且这些参数仅在运行时才知道?我会尝试举个例子。
class Messenger
{
public function sendEmail(string $email, string $subject, string $body): void { ... }
public function sendSms(string $phone, string $text): void { ... }
}
interface Command
{
public function execute(): void;
}
class SendEmailCommand implements Command
{
private readonly Messenger $messenger;
private readonly string $email;
private readonly string $subject;
private readonly string $body;
public function __constructor(Messenger $messenger)
{
$this->messenger = $messenger;
}
public function setEmail(string $email): void { $this->email = $email; }
public function setSubject(string $subject): void { $this->subject = $subject; }
public function setBody(string $body): void { $this->body = $body; }
public function execute(): void
{
$this->messenger->sendEmail($this->email, $this->subject, $this->body);
}
}
class SendSmsCommand implements Command
{
private readonly Messenger $messenger;
private readonly string $phone;
private readonly string $text;
public function __constructor(Messenger $messenger)
{
$this->messenger = $messenger;
}
public function setPhone(string $phone): void { $this->phone = $phone; }
public function setText(string $text): void { $this->text = $text; }
public function execute(): void
{
$this->messenger->sendSms($this->phone, $this->text);
}
}
在这种情况下,调用者类上有
setCommand(Command $command)
有多大用处?在某些语言中,当尝试调用
setX()
时,我什至会收到错误,因为 Command
接口没有定义它们。做这样的事情是不是一个坏主意?class EmailSendButton()
{
private readonly Messenger $messenger;
public function __constructor(Messenger $messenger)
{
$this->messenger = $messenger;
}
public function onClick(): void
{
$email = $this->getEmail();
$subject = $this->getSubject();
$body = $this->getBody();
$sendEmailCommand = new SendEmailCommand($this->messenger);
$sendEmailCommand->setEmail($email);
$sendEmailCommand->setSubject($subject);
$sendEmailCommand->setBody($body);
$sendEmailCommand->execute();
}
}
我知道在另一个类中实例化一个类并不理想,它会产生耦合,但你会如何解决它?
我正在考虑
setCommand(SendEmailCommand $sendEmailCommand)
而不是更简单的
setCommand(Command $command)
,但它增加了客户端代码的复杂性,而不是IMO的好处。看起来您想要拥有不同的命令,这些命令可以有不同的参数。我对 php 不熟悉,所以让我展示一个如何通过 C# 完成它的例子。主要思想是创建一个实现
ICommand
接口的自定义类。有了这样的课程,你可以发送任何你想要的参数。
让我们深入研究代码。这是
Command
的抽象:
public interface ICommand
{
void Execute();
}
这些是
Command
抽象的具体实现。这些实现可以有不同的参数:
class SmsCommand : ICommand
{
private string _phone;
private string _text;
private Messenger _messenger;
public SmsCommand(string phone, string text, Messenger messenger)
{
_phone = phone;
_text= text;
_messenger= messenger;
}
public void Execute()
{
_messenger.SendSms(_phone, _text);
}
}
和
EmailCommand
:
class EmailCommand : ICommand
{
private string _phone;
private string _text;
private string _subject;
private string _body;
private Messenger _messenger;
public EmailCommand(string phone, string text, string subject,
string body, Messenger messenger)
{
_phone = phone;
_text = text;
_subject = subject;
_body = body;
_messenger = messenger;
}
public void Execute()
{
_messenger.SendEmail(_phone, _text, _subject, _body);
}
}
它是
Messenger
,可以发送你想要的消息:
public class Messenger
{
public void SendEmail(string phone, string text,
string subject, string body)
{
Console.WriteLine($"EmailCommand: phone: {phone}, text: {text}" +
$" subject: {subject} , body: {body}");
}
public void SendSms(string phone, string text)
{
Console.WriteLine($"SmsCommand: phone: {phone}, text: {text}");
}
}
这是一个运行上述命令的类:
public class Invoker
{
ICommand _command;
public void SetCommand(ICommand command)
{
_command = command;
}
public void ExecuteCommand()
{
_command.Execute();
}
}
上面的代码可以这样运行:
Invoker invoker = new Invoker();
invoker.SetCommand(new SmsCommand("phone 1", "text 1", new Messenger()));
invoker.ExecuteCommand();
invoker.SetCommand(new EmailCommand("phone 1", "text 1",
"subject 1", "body 1", new Messenger()));
invoker.ExecuteCommand();
输出:可以在这里看到