This is a creation in Article, where the information may have evolved or changed.
In the previous blog design mode-singleton mode (Go language description) we introduced how to implement a singleton pattern in Golang, at the end of the article we also introduced a unique way to implement the Golang-sync. Once.do ()allows the Golang easy implementation to handle the simple interest of concurrent requests. Today we continue to explore design patterns to introduce the implementation of the command pattern .
Speaking of command, everyone's first reaction may be our usual knock on the various commands, PA PA A few lines of command down can be completed some functions, after seeing the word command mode, you may also like I think the command here is to perform some simple task function, but not, The commands here are more like the requests we make or the buttons on the TV remote. So let's take a look at the definition of the command pattern and then compare it to the actual example in life.
The command pattern is to encapsulate a request as an object, so that we can parameterize the client with different requests, queue requests or log requests, and support revocable operations. The command pattern is an object-oriented pattern with an alias of action mode or transaction mode.
There are several roles in command mode:
Command: Commands
Invoker: Caller
Receiver: Recipients
Client: Clients
Their relationship can be described in this way:
The client sends a command through the caller, and the command invokes the receiver to perform the appropriate action.
In fact, the command mode is very simple, but do not know that we found that the caller and receiver in the above description does not know the other side, that is, they are decoupled.
Or use the remote control example to explain, the remote control corresponding to the role of the caller, TV is the receiver, command it? The corresponding is the remote control button, the last client is our people, when we want to turn on the TV, the Remote Control (caller) of the power button (command) to turn on the TV ( Receiver), in this process the remote is not aware of the TV, but the power button is to know who he wants to control what operation.
... Alas, the language is not very good, suddenly found the more described the more difficult to understand it? Or use the code to implement the above remote control example. We have to compare the above characters one by one to achieve.
The receiver, which is a big TV,
// receivertypestruct{}func (p TV) Open() { fmt.Println("play...")}func (p TV) Close() { fmt.Println("stop...")}
This TV is weak, only open and close two functions, corresponding to the above code Open
and Close
two methods, although very simple, but we did create a TV (estimated or color).
Below, we will implement the command, that is, the button on the remote control, because the TV only open and close function, so the button we also only provide two, more than the use of.
// commandtypeinterface { Press()}typestruct { tv TV}func (p OpenCommand) Press() { p.tv.Open()}typestruct { tv TV}func (p CloseCommand) Press() { p.tv.Close()}
First we define a command interface, and there is only one way to Press
call this method when we press the button, and then we implement only two keys, respectively OpenCommand
, and both CloseCommand
implementations hold a TV Press
handle and method, the corresponding method of the TV is called according to the function to complete the correct operation.
What else have we not achieved? Caller, that is, the remote control, to see how the remote control to implement it.
// sendertypestruct { cmd Command}func (p *Invoker) SetCommand(cmd Command) { p.cmd = cmd}func (p Invoker) Do() { p.cmd.Press()}
In the remote control we have a Command
type of variable, and provide a SetCommand
way to set the command, then we press the key on the remote control which method? Look at the method Do
, we directly call the method of the command Press
, this time the client (that is, we people) picked up the remote control, The Open button (SetCommand) is clicked, and the button is pressed (do), and the TV is on (open).
So finally, let's see how the client is going to call it,
func main() { var tv TV openCommand := OpenCommand{tv} invoker := Invoker{openCommand} invoker.Do() invoker.SetCommand(CloseCommand{tv}) invoker.Do()}
Command mode implementation is also very simple, it reduces the coupling of our system, and we can arbitrarily expand the use of the command without the need to modify the code, the opening and closing principle embodies the incisively and vividly.
Now everyone should have an intuitive understanding of the command mode, but we have not found a problem, our remote control when using a command only set after the use, that is, each time can only use a command, there is no better way to pre-order it? This is what we are going to introduce the compound command , also known as the Macro command , the compound command is actually to save a number of commands, by traversing the collection to invoke each command separately.
funcNewopenclosecommand () *openclosecommand {varOpenClose *openclosecommand = &openclosecommand{} Openclose.cmds = Make([]command,2)returnOpenClose}typeOpenclosecommandstruct{IndexintCmds []command}func(P *openclosecommand) AddCommand (cmd Command) {P.cmds[p.index] = cmd p.index++}func(P Openclosecommand) Press () { for_, Item: =RangeP.cmds {item. Press ()}}funcMain () {varOpenClose *openclosecommand = Newopenclosecommand () Openclose.addcommand (Opencommand{tv}) OpenClose.AddCommand ( CLOSECOMMAND{TV}) invoker. SetCommand (OpenClose) invoker. Do ()}
We define a openclosecommand, where a slice is used to save each command, and the AddCommand method to add commands to the King, Openclosecommand implement the press method, so essentially he is a command, We call his press method to traverse the saved command and invoke each of the press methods.
Here, the command mode we introduced, Command mode has a very high extensibility, followed the open and close principle, so reduce the possibility of modifying the code to introduce bugs, think about where in your code you can use the command mode to solve it.