Home >Backend Development >PHP Tutorial >Understanding the Command Design Pattern
Core points
Today, more than 4 billion mobile phones are in use worldwide. In Australia alone, the population is about 11 million, while the number of mobile phones exceeds 22 million - an average of 2 mobile phones per person! It is obvious that mobile phone use is becoming more and more common. Given the popularity of smartphones and other mobile devices, more and more customers are now choosing to receive notifications via text messages rather than emails. SMS does have an advantage over emails – they are short, instant, and most importantly, spam is negligible. So, what does this have to do with the command mode? Let's look at a fictional scene. A company has a website that holds a prize-winning competition every day. It has a database of over 250,000 registered users, each user receives a password every day, which they must enter or click on the link to register for the lottery. Most users choose to receive emails, but now a considerable number of users choose to receive notifications via text messages. Here is the question: How to send messages to two groups of users through two different channels? The logical approach is to split the user into two groups, email recipients and SMS recipients, which will involve running two different queries and sending the password to each group separately. Using the command pattern that will be described in this article, you can send messages to two groups of users through a single process.
Message queue using command mode
Command mode (sometimes called action mode or transaction mode) is a design pattern that describes how requests are encapsulated as objects so that you can queue or record clients with different requests. To demonstrate how command mode works, let's use a simple example of message queues. The following is the definition of the MessageQueue class:
<?php class MessageQueue { private $queue; public function __construct() { $this->queue = array(); } public function addMessage(IMessage $msg) { $this->queue[] = $msg; } public function execute() { $sendCount = 0; foreach ($this->queue as $msg) { if ($msg->send()) { $sendCount++; } } return $sendCount; } }
Message queue provides two methods—the addMessage() method, which adds message objects to the queue; and the execute() method, which handles every message in the queue. In this example, the addMessage() method simply appends the message to the internal array $queue, while the execute() method iterates over the elements in the $queue and calls the send() method for each message object. Command mode queues each request for later processing; the actual mechanism for sending emails or text messages will be implemented in the send() method of the object. MessageQueue does not need to know how to handle the request, as this will be the responsibility of the request object. To ensure that the send() method is available, the message object must implement the IMessage interface.
<?php interface IMessage { public function send(); }
Each message object implements the IMessage interface and provides its own implementation of the send() method.
<?php class DailyAlertEmail implements IMessage { // ... public function send() { // 发送电子邮件的实际代码 // ... echo "Sending message via email\n"; } } class DailyAlertSMS implements IMessage { // ... public function send() { // 发送短信的实际代码 // ... echo "Sending message via SMS\n"; } }
DailyAlertEmail message implements its send() method to send a password as an email, while the DailyAlertSMS message object implements its send() method to send a message as a SMS message. Then, to send a message to the SMS and email recipients, you will query the database to get its communication preferences, instantiate the appropriate IMessage object and add it to the message queue, and then call the queue's execute() method. By the way, creating the correct IMessage object for users will be a good opportunity to use the factory method design pattern!
<?php // 创建一个新的队列 $msgQueue = new MessageQueue(); $result = $db->query("SELECT * FROM customers"); while ($customer = $result->fetch(PDO::FETCH_ASSOC)) { // 工厂根据用户的偏好创建DailyAlertSMS或DailyAlertEmail对象 $msg = MessageFactory::build($customer, $codeword); // 将消息对象添加到队列中 $msgQueue->addMessage($msg); } // 现在发送给所有客户 $msgQueue->execute();
Using command mode, you can retrieve all customers from the database, regardless of the customer's communication preferences, instantiate the appropriate IMessage implementations and process them at once, instead of first querying all SMS customers' databases and processing them, and then repeating this process for email customers. Remember, this is just a basic example; in real-life applications, it is better to batch process SMS and emails and send them regularly at different times of the day, ideally as background processes. With some minor modifications, you can convert it into a "delayed" message queue that runs as a cron task and use a database to monitor the progress of the process.
Summary
As you can see, the command mode is perfect for the following situations:
In this tutorial, I show you how the command pattern becomes a useful design pattern for implementing command queues, where requests can be queued for sequential processing, while decoupling the actual implementation of execution from the queue itself. Horiyan / Shutterstock
Command Design Pattern FAQ (FAQ)
Command design pattern is mainly used to decouple the sender and receiver of requests. This means that the sender does not need to know the details of the action being performed or the recipient of the request. Instead, the sender knows how to issue a command, and the command knows how to execute a request. This mode is especially useful in scenarios where you want to use operation parameterized objects and need to queue, specify, and execute requests at different times.
Command design pattern works by encapsulating requests into objects, allowing users to use queues, requests, and operations to parameterize clients. It involves four components: command, receiver, caller, and client. The command declares the interface to perform the operation, the receiver knows how to perform the operation, the caller saves the command and at some point asks the command to execute the request by calling its execute method, while the client creates a ConcreteCommand object and sets its receiver.
Command design patterns provide many benefits. It decouples the classes that call operations and objects that know how to perform operations, it allows you to create a series of commands by providing a queue system, and it allows you to control the execution of these commands. Additionally, it supports undoable operations, as each command is an object with a specific method.
Command design pattern is especially useful when you need to make a request to an object without knowing the action being requested or the recipient of the request. It is also beneficial when you need to use operation parameterized objects and need to queue, specify, and execute requests at different times.
Of course, a common example of command design patterns is implementing a menu system in a graphical user interface (GUI). Each action in the menu can be a command. When the user clicks a menu item, the command associated with the item is executed.
Although both modes encapsulate algorithms into a separate component, their purpose is different. Command mode is about separating the responsibility for issuing a command from the responsibility for executing a command, making it easier to add commands or change the execution of a command. On the other hand, the policy pattern is about defining a series of algorithms, encapsulating each algorithm, and making them interchangeable.
Yes, the command design pattern can support undoable operations. To do this, the Command class must maintain a state that reverses its effect and implements an undo method that restores the object to its previous state.
Yes, command design patterns are very useful in multithreaded programming. It allows you to encapsulate requests into objects that can then be executed in separate threads. This can greatly simplify thread synchronization.
Command design pattern is a good example of encapsulation - one of the basic principles of object-oriented design. It encapsulates requests into objects, allowing you to parameterize clients with different requests.
While command design pattern has many benefits, it is not without its shortcomings. The main disadvantage is that it causes an increase in the number of classes, because each command is represented by a separate class. This can make the system more complex and difficult to understand.
The above is the detailed content of Understanding the Command Design Pattern. For more information, please follow other related articles on the PHP Chinese website!