owned this note
owned this note
Published
Linked with GitHub
DP9 命令模式(Command Pattern)、職責鏈模式(Chain of Responsibility Pattern)
===
###### tags: `DesignPatterns`
參考
[Design Patterns Elements of Reusable Object-Oriented Software](http://www.uml.org.cn/c++/pdf/DesignPatterns.pdf)
[大話設計模式](https://www.tenlong.com.tw/products/9789866761799)
[UML工具](https://plantuml-editor.kkeisuke.com/#)
[DesignPatternsPHP](https://github.com/domnikl/DesignPatternsPHP/blob/master/Behavioral/State/OrderContext.php)
[Head First Design Patterns: A Brain-friendly Guide](https://www.books.com.tw/products/F010315469)
[汤姆大叔的博客: 深入理解JavaScript系列](https://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html)
[從實例學設計模式 by Jace Ju](http://slides.com/jaceju/design-patterns-by-examples/#/)
[设计模式之美](https://www.cnblogs.com/gaochundong/p/design_patterns.html)
[UNC-GOF](http://www.cs.unc.edu/~stotts/GOF/hires/chap1fso.htm)
[What is Dependency Injection? - Fabien Potencier](http://fabien.potencier.org/what-is-dependency-injection.html)
[十牛圖](http://enlight.lib.ntu.edu.tw/FULLTEXT/JR-BJ013/bj013543407.pdf)
# 命令模式(Command pattern)
## 大話:
### 定義: 命令模式,將一個請求封裝為一個物件,讓你可用不同的請求對客戶進行參數化;請求排隊或記錄請求日誌,以及支援可取消的操作。
#### 使用時機:
行為請求者與行為實現者的緊耦合(一人燒烤路邊攤的老闆與客人)
對請求排隊或記錄請求日誌,以及支援可取消的操作不適合時 (p.344)
## 優點:
1. 容易地設計一個命令佇列
2. 在需要的情況下,可以較容易地將命令寫入日誌
3. 允許接收請求的一方決定是否要否決請求
4. 可以容易地實現對請求的取消和重做
5. 由於加進新的具體命令類別不會影響其他的類別,因此增加新的具體命令類別很容易。
6. 最關鍵的優點是命令模式把請求一個操作的物件與知道怎麼執行一個操作的物件分割開。
(p.256)
敏捷開發原則告訴我們,不要為程式碼加上基於猜測的、實際不需要的功能。如果不清楚一個系統是否需要命令模式,就不要急著去實現它,
事實上,在需要的時候透過重構實現這個模式並不困難,只有在真正需要如取消/恢復操作等功能時,把原來的程式碼重構為命令模式才有意義。(p.256)
### 討論:
- 哪邊有用到呢?
JOB QUEUE
- 哪邊可以用?
運費設定、JOB QUEUE
## GOF
## Command Pattern
### Intent
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
### Also Known As
Action, Transaction
### Motivation
Sometimes it's necessary to issue requests to objects without knowing anything
about the operation being requested or the receiver of the request. For example,
user interface toolkits include objects like buttons and menus that carry out a
request in response to user input. But the toolkit can't implement the request
explicitly in the button or menu, because only applications that use the toolkit
know what should be done on which object. As toolkit designers we have no way of
knowing the receiver of the request or the operations that will carry it out.
有時候我們需要在不知道請求內容或是請求對象為何的情況下去對某些物件發出請求。
舉例來說,工具列功能選單有許多的按鈕物件,這些選單與按鈕物件會針對使用者輸入內容發抒請求並處理與給予回應。
但是工具列中的選單與按鈕本身並無法實現請求,因為只有使用這些選單與按鈕的程式本身才知曉依照哪些輸入而去找對應的物件處理。
設計工能列的人本身也無法事先知道接收請求的一方或是接受到的操作要求會被如何執行。
The Command pattern lets toolkit objects make requests of unspecified application
objects by turning the request itself into an object. This object can be stored
and passed around like other objects. The key to this pattern is an abstract Command
class, which declares an interface for executing operations. In the simplest form
this interface includes an abstract Execute operation. Concrete Command
subclasses specify a receiver-action pair by storing the receiver as an
instance variable and by implementing Execute to invoke the request. The receiver
has the knowledge required to carry out the request.
命令模式透過將請求本身也轉換成物件,可以使一個工具包物件在面對來自未定義的程式時也能發出請求。
且這個物件可以像其他物件依樣被儲存以及傳遞。命令模式的實現最關鍵的一點就是定義了執行操作的介面的抽象命令類別。
實例化的命令類別透過儲存一組定義接收命令者的實體變數與透過實作命令去處理到來的請求。
而接收命令者明白這個請求會怎麼被處理。

Menus can be implemented easily with Command objects. Each choice ina Menu is
an instance of a MenuItem class. An Application class creates these menus and their
menu items along with the rest of the user interface.The Application class also
keeps track of Document objects that a user hasopened.
The application configures each MenuItem with an instance of a concrete Command
subclass. When the user selects a MenuItem, the MenuItem calls Execute on its
command, and Execute carries out the operation. MenuItems don't know which subclass
of Command they use.Command subclasses store the receiver of the request and invoke
one or more operations on the receiver.
For example, PasteCommand supports pasting text from the clipboard into a Document.
PasteCommand's receiver is the Document object it is supplied upon instantiation.
The Execute operation invokes Paste on the receiving Document.

OpenCommand's Execute operation is different: it prompts the userfor a document
name, creates a corresponding Document object, adds the document to the receiving
application, and opens the document.

Sometimes a MenuItem needs to execute a **sequence** of commands.For example, a
MenuItem for centering a page at normal size could beconstructed from a
CenterDocumentCommand object and a NormalSizeCommand object. Because it's common
to string commands together in this way, we can define a MacroCommand class to
allow a MenuItem to execute an open-ended number of commands. MacroCommand isa
concrete Command subclass that simply executes a sequence ofCommands. MacroCommand
has no explicit receiver, because the commandsit sequences define their own
receiver.

In each of these examples, notice how the Command pattern decouples the object
that invokes the operation from the one having the knowledge to perform it. This
gives us a lot of flexibility in designing our user interface. An application can
provide both a menuand a push button interface to a feature just by making the
menu andthe push button share an instance of the same concrete Command subclass.We
can replace commands dynamically, which would be useful forimplementing
context-sensitive menus. We can also support command scripting by composing
commands into larger ones. All of this is possible because the object that issues
a request only needs to know how to issue it; it doesn't need to know how the request
will be carried out.
### Applicability
Use the Command pattern when you want to
- **parameterize objects by an action to perform, as MenuItem objects did above.**
You can express such parameterization in a procedural language with a
**callback** function, that is, a function that's registered somewhere to be
called at a later point. Commands are an object-oriented replacement for
callbacks.
可以拿來取代作為OOP中取代程序導向中的 callback 功能使用,將參數化物件的動作用命令封裝起來。
- **specify, queue, and execute requests at different times.** A Command object
can have a lifetime independent of the original request. If the receiver
of a request can be represented in an address space-independent way, then
you can transfer a command object for the request to a different process
and fulfill the request there.
在被執行者(接收者)與命令可以有不同週期的時候,就可以考慮使用,,例如 queue 處理、排程處理等。
- **support undo. The Command's Execute operation can store state for reversing
its effects in the command itself.** The Command interface must have an added
Unexecute operation that reverses the effects of a previous call to Execute.
Executed commands are stored in a history list. Unlimited-level undo and
redo is achieved by traversing this list backwards and forwards calling
Unexecute and Execute, respectively.
在需要支援取消、回復功能時,也可以使用。搭配將每一次的改變狀態儲存起來,配合分別實作 執行 與 反執行 可以達到有彈性的狀態轉換。
- **support logging changes so that they can be reapplied in case of a system crash.**
By augmenting the Command interface with load and store operations,
you can keep a persistent log of changes. Recovering from a crash involves
reloading logged commands from disk and reexecuting them with the Execute
operation.
支援當系統異常發生非預期中斷時,能透過記錄執行前後變化的 LOG,去還原系統。
- **structure a system around high-level operations built on primitives operations.**
Such a structure is common in information systems that support
transactions. A transaction encapsulates a set of changes to data. The
Command pattern offers a way to model transactions. Commands have a common
interface, letting you invoke all transactions the same way. The pattern
also makes it easy to extend the system with new transactions.
在原生系統上,建構更高階層的操作,例如支援 commit、rollback 的交易系統等。
### Structure

### Participants
- **Command**
- declares an interface for executing an operation.
- **ConcreteCommand (PasteCommand, OpenCommand)**
- defines a binding between a Receiver object and an action.
- implements Execute by invoking the corresponding operation(s) on Receiver.
- **Client (Application)**
- creates a ConcreteCommand object and sets its receiver.
- **Invoker (MenuItem)**
- asks the command to carry out the request.
- **Receiver (Document, Application)**
- knows how to perform the operations associated with carrying out a request. Any class may serve as a Receiver.
---
- **Command**
- 宣告一個可執行操作的介面
- **ConcreteCommand (PasteCommand, OpenCommand)**
- 定義被操作的物件與操作之間的綁定關係
- 實作可執行的命令,並調用命令操作被操作者。
- **Client (Application)**
- 建立一個實體的命令物件,並設定將被該命令物件操作的接收方。
- **Invoker (MenuItem)**
- 使命令回應請求並執行
- **Receiver (Document, Application)**
- 對於請求與執行結果明白如何表現。任何類別都可能當作 Receiver 服務接受其他請求。
### Collaborations
- The client creates a ConcreteCommand object and specifies its receiver.
- An Invoker object stores the ConcreteCommand object.
- The invoker issues a request by calling Execute on the command. When commands are undoable, ConcreteCommand stores state for undoing the command prior to invoking Execute.
- The ConcreteCommand object invokes operations on its receiver to carry out the request.
The following diagram shows the interactions between these objects. It illustrates
how Command decouples the invoker from the receiver(and the request it carries
out).

### Consequences
The Command pattern has the following consequences:
1. Command decouples the object that invokes the operation from the one that knows how to perform it.
2. Commands are [first-class](https://en.wikipedia.org/wiki/First-class_citizen) objects. They can be manipulated and extendedlike any other object.
3. You can assemble commands into a composite command. An example is theMacroCommand class described earlier. In general, composite commandsare an instance of the Composite (183) pattern.
4. It's easy to add new Commands, because you don't have to changeexisting classes.
### Implementation
Consider the following issues when implementing the Command pattern:
1. **How intelligent should a command be?** A command can have a wide range of
abilities. At one extreme itmerely defines a binding between a receiver
and the actions that carryout the request. At the other extreme it implements
everything itself without delegating to a receiver at all. The latter extreme
is useful when you want to define commands that are independent of
existingclasses, when no suitable receiver exists, or when a command knows
its receiver implicitly. For example, a command that creates
another application window may be just as capable of creating the window
as any other object. Somewhere in between these extremes are commands that
have enough knowledge to find their receiver dynamically.
2. **Supporting undo and redo.** Commands can support undo and redo capabilities
if they provide a way to reverse their execution (e.g., an Unexecute or Undo
operation). A ConcreteCommand class might need to store additional state
to do so. Thisstate can include
- the Receiver object, which actually carries out operations in response to the request,
- the arguments to the operation performed on the receiver, and
- any original values in the receiver that can change as a result of
handling the request. The receiver must provide operations that let
the command return the receiver to its prior state.
To support one level of undo, an application needs to store only the command
that was executed last. For multiple-level undo and redo, the application
needs a **history list** of commands that have been executed, where the maximum
length of the list determines the number of undo/redo levels. The history
list stores sequences of commands that have been executed. Traversing
backward through the list and reverse-executing commands cancels their
effect; traversing forward and executing commands reexecutes them.
An undoable command might have to be copied before it can be placed on the
history list. That's because the command object that carried out the original
request, say, from a MenuItem, will perform other requests at later times.
Copying is required to distinguish different invocations of the same command
if its state can vary a cross invocations.
For example, a DeleteCommand that deletes selected objects must
store different sets of objects each time it's executed. Therefore
the DeleteCommand object must be copied following execution, and the copy is
placed on the history list. If the command's state never changes on execution,
then copying is not required—only a reference to the command need be placed
on the history list. Commands that must be copied before being placed on
the history list act as prototypes (see Prototype (133)).
3. **Avoiding error accumulation in the undo process.** Hysteresis can be a problem
in ensuring a reliable,semantics-preserving undo/redo mechanism. Errors
can accumulate ascommands are executed, unexecuted, and reexecuted
repeatedly so thatan application's state eventually diverges from original
values. Itmay be necessary therefore to store more information in the
command to ensure that objects are restored to their original state. The
Memento (316) pattern can be applied to give the command access to this
information without exposing the internals of other vobjects.
4. **Using C++ templates.** For commands that (1) aren't undoable and (2) don't
require arguments,we can use C++ templates to avoid creating a Command
subclass forevery kind of action and receiver. We show how to do this in
the SampleCode section.
### Known Uses
Perhaps the first example of the Command pattern appears in a paper by Lieberman
[Lie85]. MacApp [App89] popularizedthe notion of commands for implementing
undoable operations.ET++ [WGM88], InterViews [LCI+92], andUnidraw [VL90] also
define classes that follow the Command pattern. InterViews defines an Action
abstract class that provides command functionality. It also defines an
ActionCallbacktemplate, parameterized by action method, that can instantiate
command subclasses automatically.
The THINK class library [Sym93b] also uses commands to supportundoable actions.
Commands in THINK are called "Tasks." Taskobjects are passed along a Chain of
Responsibility (251) for consumption.
Unidraw's command objects are unique in that they can behave like messages. A
Unidraw command may be sent to another object for interpretation, and the result
of the interpration varies with the receiving object. Moreover, the receiver may
delegate theinterpretation to another object, typically the receiver's parent
in alarger structure as in a Chain of Responsibility. The receiver of aUnidraw
command is thus computed rather than stored. Unidraw'sinterpretation mechanism
depends on run-time type information.
Coplien describes how to implement functors, objects thatare functions, in C++
[Cop92]. He achieves a degree oftransparency in their use by overloading the
function call operator(operator()). The Command pattern is different; its focusis
on maintaining a binding between a receiver and a function(i.e., action), not
just maintaining a function.
### Related Patterns
- A Composite (183)can be used to implement MacroCommands.
- A Memento (316)can keep state the command requires to undo its effect.
- A command that must be copied before being placed on the historylist acts as a Prototype (133).
-------------
# 職責鏈模式(Chain of Responsibility Pattern)
## 大話:
### 定義: 職責鏈模式,使多個物件都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這個物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個物件處理它為止。
容易發生變化,可以將各公司管理者類別做成管理者的子類別,利用多型來化解分支帶來的僵化(p.363)
發出請求的用戶端並不知道這當中的哪一個物件最終處理這個請求,
這樣系統的更改可以在不影響用戶端的情況下動態地重新組織和分配責任。(p.363)
### 好處:
當客戶提交一個請求時,請求是沿鏈傳遞直至有一個 ConcreteHandler 物件負責處理它。
接受者和發送者都沒有對方的明確資訊,且鏈中的物件自己也並不知道鏈的結構。結果是職責鏈可簡化物件的相互連接,他們僅須保持一個指向其後繼者的參考,而不需保持它所以有的候選接受者的參考,也就大大降低了耦合度。
由於是用戶端定義職責鏈的結構,也就是說,可以隨時地增加或修改處理一個請求的結構。增強了給物件指派職責的靈活性。
一個請求極有可能到了鏈的末端都得不到處理,或者因為沒有正確配製而得不到處理,因此需事先考慮全面。 (p.367)
#### 使用時機:
### 討論:
- 哪邊有用到呢?
博弈 假現金 信用額度 一層一層 放款 核准
- 哪邊可以用?
客服系統 請假系統(超過三天 往上) 工單系統
## GOF
## Command Pattern
### Intent
### Also Known As
### Motivation
### Applicability
### Structure
### Participants
### Collaborations
### Consequences
### Implementation
### Known Uses
### Related Patterns