杜嘉豪
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee
  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    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. 命令模式透過將請求本身也轉換成物件,可以使一個工具包物件在面對來自未定義的程式時也能發出請求。 且這個物件可以像其他物件依樣被儲存以及傳遞。命令模式的實現最關鍵的一點就是定義了執行操作的介面的抽象命令類別。 實例化的命令類別透過儲存一組定義接收命令者的實體變數與透過實作命令去處理到來的請求。 而接收命令者明白這個請求會怎麼被處理。 ![](https://i.imgur.com/eJ4tuGN.png) 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. ![](https://i.imgur.com/KSbZsG8.png) 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. ![](https://i.imgur.com/F3VB9Su.png) 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. ![](https://i.imgur.com/scu0mXM.png) 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 ![](https://i.imgur.com/1DSq7Vs.png) ### 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). ![](https://i.imgur.com/6Le4JZV.png) ### 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

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully