处理不同参数时如何使用命令模式

问题描述 投票:0回答:1

查看herehere报告的命令模式的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的好处。
    

design-patterns
1个回答
0
投票
我知道在另一个类中实例化一个类并不理想,它会产生耦合,但你会如何解决它?

看起来您想要拥有不同的命令,这些命令可以有不同的参数。我对 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();

输出:

关于命令模式的精彩文章

可以在这里看到

© www.soinside.com 2019 - 2024. All rights reserved.