Kimn
    • 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

      This note has no invitees

    • 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
    • Note Insights New
    • Engagement control
    • Make a copy
    • 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 Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy 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

    This note has no invitees

  • 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
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- ###### tags: `Design Pattern` --- # 11/02 ## 外觀模式 ### 概述 - 有些人可能炒過股票,但其實大部分人都是不太懂裡面的一些操作的,這種沒有足夠了解證券知識的情況下炒股票是很容易虧錢的,剛開始炒股時我們肯定都會想,如果有個懂行的幫幫手就好了,其實基金就是個好幫手,支付寶裡就有許多的基金,它將投資者分散的資金集中起來,交由專業的經理人進行管理,投資於股票、債券、外匯等領域,而基金投資的收益歸持有者所有,管理機構則是收取一定比例的託管管理費用。 ### 定義 - 外觀模式又名門面模式,是一種==通過為多個複雜的子系統提供一個一致的接口,而使這些子系統更加容易被訪問的模式。== - 該模式對外有一個統一的接口(你可以將其理解為上例中的基金,具體基金裡面到底是投資股票,還是債券,還是外匯,咱們並不關注,因為這是由子系統來實現的),外部應用程序不用關心內部子系統的具體的細節,這樣就大大降低了應用程序的複雜度,並提高了程序的可維護性。 - 外觀模式(Facade)是“迪米特法則”的典型應用。 ![](https://i.imgur.com/3I0oXCB.png) ### 結構 外觀模式包含以下主要角色: - 外觀(Facade)角色:為多個子系統對外提供一個共用接口。 - 子系統(Sub System)角色:實現系統的部分功能,客戶可以通過外觀角色訪問他。 ### 案例 :::info 例:智能家電控制 - 小明的爺爺已經60歲了,一個人在家生活:每次都需要打開燈、打開電視、打開空調;睡覺時關閉燈、關閉電視、關閉空調;操作起來都比較麻煩。 - 所以小明給爺爺買了一個智能音箱,可以通過語音直接控制這些智能家電的開啟和關閉。 - 類圖如下: ![](https://i.imgur.com/NAss4UU.png) ::: ```typescript= // 子系統類 class Light { on(): void {...}; off(): void {...}; } class TV { on(): void {...}; off(): void {...}; } class AirCondition { on(): void {...}; off(): void {...}; } // 外觀類,用戶主要和該類物件進行交互 class SmartAppliancesFacade { // 聚合電燈、電視機、空調物件 private light: Light; private tv: TV; private airCondition: AirCondition; constructor() { this.light = new Light(); this.tv = new TV(); this.airCondition = new AirCondition(); } // 通過語音控制 say(message: string): void { if (message.includes("打開")) { this.on(); } else if (message.includes("關閉")) { this.off(); } else { console.log("我聽不懂"); } } // 一鍵打開功能 private on(): void { this.light.on(); this.tv.on(); this.airCondition.on(); } // 一鍵關閉功能 private off(): void { this.light.off(); this.tv.off(); this.airCondition.off(); } } class Client { static main(): void { const facade = new SmartAppliancesFacade(); facade.say("打開家電"); console.log("-------------"); facade.say("關閉家電"); facade.say("測試"); } } Client.main(); ``` - 優點: - 降低了子系統與客戶端之間的耦合度(很顯然,這是由外觀類來降低的),使得子系統的變化不會影響調用它的客戶端 - 對客戶屏蔽了子系統組件,減少了客戶處理的對像數目(如果客戶直接去訪問這些子系統的話,那麼就可能要去訪問不同的子系統裡面的多個物件了,這還是比較麻煩的),並使得子系統使用起來更加容易 - 缺點: - 不符合開閉原則,修改很麻煩。 ### 使用場景 - 對分層結構系統構建時,使用外觀模式定義子系統中每層的入口點可以簡化子系統之間的依賴關係。 - 當一個複雜系統的子系統很多時,外觀模式可以為系統設計一個簡單的接口供外界訪問。(框架) - 當客戶端與多個子系統之間存在很大的聯繫時,引入外觀模式可將它們分離,從而提高子系統的獨立性和可移植性。 ## 組合模式 ### 概述 ![](https://i.imgur.com/cM3ytAD.png) - 上圖我們可以看作是一個文件系統,對於這樣的結構我們可以稱為樹狀結構。在樹狀結構中可以通過調用某個方法來遍歷整個樹,當我們找到某個葉子節點後,就可以對葉子節點進行相關的操作。 - 可以將這棵樹理解成一個大的容器,容器裡面包含很多成員物件,這些成員物件即可是容器物件也可以是葉子物件。但是由於容器物件和葉子物件在功能上的區別,使得我們在使用過程中必須要區分容器和葉子物件,但這樣就會給客戶帶來不必要的麻煩,==作為客戶,他始終希望能夠一致的對待容器物件和葉子物件。== - 組合模式就是為了解決此問題。 ### 定義 - 組合模式又名部分整體模式,是用於把一組相似的物件當作一個單一的物件。組合模式依據樹形結構來組合物件,用來表示部分以及整體層次,這種類型的設計模式屬於結構型模式,它創建了物件組的樹形結構。 ### 結構 組合模式主要包含三種角色: - 抽像根節點(Component):定義系統各層次物件具有的共有方法和屬性,可以預先定義一些默認行為和屬性。 怎麼來理解抽像根節點呢?還是通過上圖來理解,不管是文件夾還是文件,我們都可以向上抽取,抽取出一個抽像類,而在這個抽像類裡面,我們就可以去定義文件和文件夾中的共有行為和屬性了。也就是說,正是因為客戶他想要一致的去對待容器物件和葉子物件,所以他就可以定義出這麼一個公共的抽像類了 - 樹枝節點(Composite):定義樹枝節點的行為,即存儲子節點,組合樹枝節點和葉子節點形成一個樹形結構。 - 葉子節點(Leaf):葉子節點物件,其下再無分支,是系統層次遍歷的最小單位。 ### 案例 :::info 例:軟體菜單 - 我們在訪問別的一些管理系統時,經常可以看到類似的菜單。一個菜單可以包含菜單項(菜單項是指:不再包含其他內容的菜單條目),也可以包含帶有其他菜單項的菜單,因此使用組合模式描述菜單就很恰當,我們需求是針對一個菜單,打印出其包含的所有菜單以及菜單項的名稱。 - 要實現該案例,我們先畫出類圖 ![](https://i.imgur.com/A9IycJM.png) ::: ![](https://i.imgur.com/wuppLLw.png) - 實現效果 ![](https://i.imgur.com/XjbJi7m.png) ### 分類 在使用組合模式時,根據抽象構建類的定義模式,我們可將組合模式分為透明組合模式和安全組合模式。 - 透明組合模式 - 在透明組合模式中,抽像根節點角色中聲明了所有用於管理成員物件的方法,==比如在以上示例中 MenuComponent 抽像類聲明了 add、remove 、getChild 等方法==,這樣做的好處是確保所有的構件類都有相同的接口。 - 當使用的時候,就不需要再去區分菜單還是菜單項了,直接面向抽象編程即可。 - 透明組合模式也是組合模式的標準形式,所以我們在使用的時候盡量都使用透明組合模式。 - 透明組合模式的缺點是不夠安全,因為葉子物件和容器對像在本質上是有區別的,葉子對像不可能有下一個層次的物件,即不可能包含成員物件,因此為其提供 add、remove 等方法是沒有任何意義的,雖然這在編譯階段不會出錯,但是在運行階段如果調用這些方法,那麼可能就會出錯(如果沒有提供相應的錯誤處理代碼) - 安全組合模式 - 在安全組合模式中,在抽象構件角色中沒有聲明任何用於管理成員物件的方法,而是在樹枝節點 Menu 類中聲明並實現這些方法。 - 安全組合模式的缺點是不夠透明,因為葉子構件和容器構件具有不同的方法,且容器構件中那些用於管理成員物件的方法沒有在抽象構件類中定義,因此客戶端不能完全針對抽象編程,必須去區別對待葉子構件和容器構件。 - 懶人包:抽象類有定義資料夾的方法->透明,反之-> 不透明 ### 優點 - 組合模式可以清楚地定義分層次的複雜物件,表示物件的全部或部分層次,它讓客戶端忽略了層次的差異,方便對整個層次結構進行控制。 - 客戶端可以一致地使用一個組合結構或其中單個物件,不必關心處理的是單個對像還是整個組合結構,簡化了客戶端代碼。 - 在組合模式中增加新的樹枝節點和葉子節點都很方便,無須對現有類庫進行任何修改,符合"開閉原則"。 - 組合模式為樹形結構的物件導向實現提供了一種靈活的解決方案,通過葉子節點和樹枝節點的遞歸組合,可以形成複雜的樹形結構,但對樹形結構的控制卻非常簡單。 ### 使用場景 - 組合模式正是應==樹狀結構==而生,所以組合模式的使用場景就是出現樹形結構的地方。 - 比如文件目錄顯示、多級目錄呈現等樹形結構數據的操作。 ## 享元模式 ### 定義 - 運用==共享技術==來有效地支持大量細粒度物件的複用。它通過共享已經存在的物件來大幅度==減少需要創建的物件數量==、避免大量相似物件的開銷,從而提高系統資源的利用率。 - 例:ubike 共享單車 ### 結構 享元(Flyweight)模式中存在以下兩種狀態: - 內部狀態(或者內部數據),即不會隨著環境的改變而改變的可共享部分。 - 外部狀態(或者外部數據),指隨環境改變而改變的不可以共享的部分。 享元模式主要有以下幾個角色: - 抽象享元角色(Flyweight):通常是一個接口或抽像類,在抽象享元類中聲明了具體享元類裡面公共的方法,這些方法可以向外界提供享元物件的內部數據(內部狀態),同時也可以通過這些方法來設置外部數據(外部狀態)。 - 具體享元(Concrete Flyweight)角色:它實現了抽象享元類,稱為享元物件;在具體享元類中為內部狀態提供了存儲空間,這是因為內部狀態是在內部進行一個存儲的,並且每個人在使用的時候,內部狀態都是一樣的。==通常我們可以結合單例模式來設計具體享元類,為每一個具體享元類提供唯一的享元物件。== - 非享元(Unsharable Flyweight)角色:並不是所有的抽象享元類的子類都需要被共享,不能被共享的子類可設計為非共享具體享元類;當需要一個非共享具體享元類的物件時,可以直接通過實例化創建,也就是說我們可以直接去創建該類的物件。 - 享元工廠(Flyweight Factory)角色:負責創建和管理享元角色。當客戶物件請求一個享元物件時,享元工廠檢査系統中是否存在符合要求的享元物件,若存在則提供給客戶;若不存在的話,則直接創建一個新的享元物件。 :::info 例:俄羅斯方塊 - 如果在俄羅斯方塊這個遊戲中,每個不同的方塊都是一個實例物件,這些物件就要佔用很多記憶體空間,下面利用享元模式進行實現。 ![](https://i.imgur.com/XvRcaMY.png) ![](https://i.imgur.com/LosbhaB.png) ::: ```typescript= // 抽象享元角色 abstract class AbstractBox { // 獲取圖形方法 abstract getShape(): string; display(color: string): void { console.log(`方塊形狀${this.getShape()},顏色:${color}`); } } // 具體享元角色 class IBox extends AbstractBox { getShape(): string { return "I"; } } class LBox extends AbstractBox {...} class OBox extends AbstractBox {...} // 工廠類,將該類設計為單例 class BoxFactory { private map: Map<string, AbstractBox>; // 在構造方法中進行初始化操作 private constructor() { this.map = new Map<string, AbstractBox>(); this.map.set("I", new IBox()); this.map.set("L", new LBox()); this.map.set("O", new OBox()); } // 提供一個方法獲取工廠類物件 static getInstance(): BoxFactory { return this.factory; } // 餓漢式 private static factory: BoxFactory = new BoxFactory(); // 根據名稱獲取圖刑物件 getShape(name: string): AbstractBox { const item = this.map.get(name); if (item == undefined) { throw new Error("沒有此圖型"); } return item; } } class Client { static main(): void { const box1 = BoxFactory.getInstance().getShape("I"); box1.display("灰色"); const box2: AbstractBox = BoxFactory.getInstance().getShape("L"); box2.display("綠色"); const box3: AbstractBox = BoxFactory.getInstance().getShape("O"); box3.display("藍色"); const box4: AbstractBox = BoxFactory.getInstance().getShape("O"); box4.display("紅色"); console.log(`兩次獲取到的圖形物件是否是同一個:${box3 === box4}`); } } Client.main(); ``` ### 優缺點、使用場景 1. 優點 - 極大減少記憶體中相似或相同物件數量,節約系統資源,提供系統性能。 - 享元模式中的外部狀態(顏色)相對獨立,且不影響內部狀態(形狀) 2. 缺點 - 為了使物件可以共享,需要將享元物件的部分狀態外部化(顏色外部化),分離內部狀態和外部狀態,使程序邏輯複雜 3. 使用場景 - 一個系統有大量相同或者相似的物件,造成記憶體的大量耗費。 - 物件的大部分狀態都可以外部化,可以將這些外部狀態傳入物件中。 - 在使用享元模式時需要維護一個儲存享元物件的享元池(HasHMap),而這需要耗費一定的系統資源,因此,應當在==需要多次重複使用享元物件時==才值得使用享元模式。

    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