杜嘉豪
    • 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
    DP3 樣板模式、範本模式 === ###### tags: `DesignPatterns` # 樣板模式、範本模式 封裝演算法 ```java= public class Cofee { void prepareRecipe() { boilWater(); brewCoffeeGrinds(); pourInCup(); addSugarAndMilk(); } public void boilWater() { System.out.ppringln("Boiling Water"); } public void rewCoffeeGrinds() { System.out.ppringln("Dripping Coffee through filtere"); } public void pourInCup() { System.out.ppringln("Pouring into cup"); } public void boilWater() { System.out.ppringln("Adding Sugar and Milk"); } } ``` ```java= public class Tea { void prepareRecipe() { boilWater(); steepTeaBag(); pourInCup(); addLemon(); } public void boilWater() { System.out.ppringln("Boiling Water"); } public void steepTeaBag() { System.out.ppringln("Steeping the tea"); } public void addLemon() { System.out.ppringln("Adding Lemon"); } public void pourInCup() { System.out.ppringln("Pouring into cup"); } } ``` ```uml @startuml class CaffeineBeverage { +prepareRecipe() +boilWater() +pourInCup() } class Coffee { +prepareRecipe() +brewCoffeeGrinds() +addSugarAndMilk() } class Tea { +preapareRecipe() +steep TeaBag() +addLemon() } CaffeineBeverage <|- Coffee CaffeineBeverage <|- Tea @enduml ``` 將 prepareRecipe() 抽象化 浸泡 steep 和 沖泡 brew 差異不大,加糖和加牛奶也很相似,可以統一用新方法取代。 ```java= // 咖啡因飲料 public abstract class CaffeineBeverage { // 同一個步驟處理茶與咖啡,因為不希望被子類別推翻,宣告為 final final void prepareRecipe() { boilWater(); brew(); pourInCup(); addCondiments(); } // 因茶與咖啡沖泡做法不同,宣告為抽象,留給子類別去實作 abstract void brew(); abstract void addCondiments(); void boilWater() { System.out.ppringln("Boiling Water"); } void pourInCup() { System.out.ppringln("Pouring into cup"); } } // 茶繼承咖啡因飲料 public class Tea extends CaffeineBeverage { public void brew() { System.out.pringln("Steeping the tea"); } public void add Condiments() { System.out.pringln("Adding Lemon"); } } // 咖啡繼承咖啡因飲料 public class Coffee extends CaffeineBeverage { public void brew() { System.out.pringln("Dripping Coffee through filter"); } public void add Condiments() { System.out.pringln("Adding Sugar adn Milk"); } } ``` 繼承為類別層次(class hierarchy)內部帶來了巨大的靈活性,通過覆寫類別或方法,根據呼叫的是哪個範例,呼叫同樣的類別方法可以得到完全不同的結果。 但有時候,我們可能需要類別或方法保持不變。希望類別或方法完成確定不變的功能,擔心覆寫它會破壞這個功能,那麼需要使用 final 關鍵字。 final 關鍵字可以終止類別的繼承,final 類別不能有子類別,final 方法不能被覆寫。 ## 樣板方法定義了一個演算的步驟,並允許次類別為一個或多個步驟,提供其實踐方式。 不透過樣板方法實踐 v.s 透過樣板方法實踐 | 不透過樣板方法實踐 | 透過樣板方法實踐 | | -------- | -------- | | Coffee、Tea 主導一切;控制演算法 | CaffeineBeverage 類別主導一切,擁有演算法,且保護演算法 | | Coffee、Tea 存在重複程式碼 | 對次類別來說,CaffeineBeverage 類別的存在可以將程式碼再用率極大化 | | 修改演算法需修改次類別許多地方 | 演算法只存在一個地方,容易修改 | | 類別不具彈性,加入新種類的咖啡因飲料,會有許多重工要做 | 樣板提供框架,可以整合其他咖啡因飲料,新咖啡因飲料只要實踐自己的方法即可 | | 演算返的知識、實踐方式,分散在許多類別中 | CaffeineBeverage 類別專注在演算法本身,而由次類別提供完整的實踐 | --- ## 樣板方法的定義 - **樣板方法模式將一個演算法的股價定義在一個方法中,而演算法本身會用到的一些方法,則是定義在次類別中。樣板方法讓次類別在不改變演算法架構的情況下,重新定義演算法中的某些步驟。** --- ```uml @startuml class AbstractClass { templateMethod() primitiveOperation1() primitiveOperation2() } // 具象類別實踐抽象方法,當樣板方法需要這兩個抽象方法時,會去呼叫他們 class ConcreteClassA { primitiveOperation1() primitiveOperation2() } // 每個具象費別都實踐了全部的抽象方法,如此一來樣板方法才能夠順利運作 class ConcreteClassB { primitiveOperation1() primitiveOperation2() } AbstractClass <|- ConcreteClassA AbstractClass <|- ConcreteClassB @enduml ``` ```java= abstract class AbstractClass { final void templateMethod() { primitiveOperation1(); primitiveOperation2(); concreteOperation(); } abstract void primitiveOperation1(); abstract void primitiveOperation2(); void concreteOperation() { //implementaion here } } ``` ```java= // 宣告一個抽象類別作為基底類別,其次類別必須實踐其抽象方法 abstract class AbstractClass { // 宣告為 fianl , 避免次類別改變此演算法架構 final void templateMethod() { // 樣板方法定義了一連串步驟。每個步驟代表一個方法 primitiveOperation1(); primitiveOperation2(); concreteOperation(); hook(); } // 次類別必須各自實踐 abstract void primitiveOperation1(); // 次類別必須各自實踐 abstract void primitiveOperation2(); // 所有次類別具有同樣做法 void concreteOperation() { //implementaion here } // 可以有預設不做事的具象方法,這種方法稱之為 hook ,次類別可以自行決定要不要推翻(override) hook 的內容 void hook() {} } ``` #### 對樣板方法進行 hook hook 是一種方法,被宣告在抽象類別中,且被定義為甚麼都不用做,或是有預設的實踐方式。 掛鉤的存在,可以讓次類別有能力對演算法進行掛勾。要不要掛勾,由次類別自行決定。 ```java public abstract class CaffeineBeverageWithHook { voic prepareRecipe() { boilWater(); brew(); pourInCup(); if (customerWantsCondiments()) { addCondiments(); } } abstract void brew(); abstract void addCondiments(); void boilWater() { System.out.ppringln("Boiling Water"); } void pourInCup() { System.out.ppringln("Pouring into cup"); } boolena customerWantsCondiments() { return true; } } ``` #### use hook ```java= public class CoffeeWithHook extends CaffeineBeverageWithHook { public void brew() { System.out.println("Dripping Coffee through filter"); } public void addCondiments() { System.out.println("Adding Sugar and Milk"); } // 推翻了掛勾方法,提供了自己想要的功能 public boolean customerWantsCondiments() { String answer = getUserInput(); if (answer.toLowerCase().startWith("y")) { return true; } else { return false; } } private String getUserInput() { String answer = null; System.out.pring("Would you like milk and sugar with your coffee (y/n)? "); BufferedReader in = new BufferedReader(new InputStreamReader(Systme.in)); try { answer = in.readLine(); } catch (IOException ioe) { System.err.println("IO error trying to read your answer") } if (answer == null) { return "no"; } return answer; } } ``` 但這個範例中,詢問顧客的功能應該可以放到超類別中,讓所有子類別共享 --- Q:建立一個樣板模式時,何時應該使用抽象方法,何時應該使用掛勾? A:當你的次類別 **"必須"** 提供演算法用在某個方法或步驟的實踐時,就使用抽象方法。 如果演算法的這個部分是選擇性的,就用掛勾。如果是掛鉤的話,次類別可以選擇實踐這個掛勾,但並不強制這麼做。 Q:掛鉤的真正目的是什麼? A:掛勾有一些使用時機。如我們之前所說的,掛勾可以讓次類別實踐演算法中選擇性的部分,或者在掛勾對於次類別的實踐並不重要的時候,次類別可以對此掛勾置之不理。掛鉤的另一個使用時機,是讓次類別能夠有機會對於樣板方法中某個即將發生的步驟(或剛發生)做出反應。 例如允許次類別進行某一種操作,或是讓次類別有能力對其抽象的超類別做出一些決定。 Q:次類別必須實踐抽象類別中的所有方法嗎? A:是的,每個具象的次類別都必須對所有抽象方法提供完整實踐,否則樣板中的算法無法正常運作。 Q:抽象方法的數量是否越少越好,否則次類別中將要做許多實踐。 A:透過讓演算法內的步驟不要切割得太細,但如果步驟太少,則又會失去彈性,所以要看狀況。 另外某些選擇性的步驟可以將這些步驟實踐成掛勾,而不是將他們實踐成收抽象方法,這樣就可以讓次類別的負荷減輕一些。 --- ### 好萊塢守則 別呼叫我們,我們會呼叫你。 好萊塢守則目的在於防止依賴腐敗,在好萊塢守則下,允喜低階元件將自己掛勾到系統上,並由高階元件決定並控制何時會用到低階元件。 如此一來可以避免高階元件一類低階元件,低階元件依賴高階元件,高階元件又依賴側邊的元件,側邊的元件又依賴低階元件諸如此類的情況。 Q: 好萊塢守則和依賴反轉原則的關係為何? A: IOC教我們避免使用具象類別,而多使用抽象,針對界面寫程式,而不是針對實踐。 而好萊塢守則則是用在建立框架貨源漸,好讓低階的元件能夠被掛勾近系統,同時又不會讓高階的元件依賴低階元件,兩者都是在於鬆綁, 但是IOC相當堅持瑜如何在設計中避免相依性。好萊塢守則則是教我們既練一個有彈性的設計,允許低階元件被掛勾近來,同時又不讓高階元件太過依賴低階元件。 Q:低階元件不可以呼叫高階元件中的方法? A:不一定。事實上,低階元件在結束時,常常會呼叫超類別中繼成來的方法。我們所要做的是壁面高低階元件之間有明顯的互相依賴,也就是同時存在高階依賴低階,低階也依賴高階的情形。 --- 比較: 樣板:次類別決定如何實踐演算法中的某些步驟 策略:將可互換的行為封裝起來,然後使用委託的方式決定要採取哪一個行為 工廠:由次類別決定實體化哪個具象類別 樣板方法 V.S 策略模式 策略模式定義一個演算法家族,並讓這些演算法可以互換。正因為每一個演算法都被封裝起來,所以客戶可以輕易地使用不同的演算法。 樣板模式定義一個演算法的大鋼,而由次類別中定義其中某些(抽象)步驟的內容,這麼一來,次類別可以有不同的實踐細節,但是演算法的季夠依然維持不變。 策略模式必須放棄對演算法的控制, 但策略模式的依賴度較低,透過物件合成的方式,使用者可以在執行期透過使用不同的策略物件改變演算法。 樣板模式在超類別中提供了一個基礎的方法,達到程式碼的再用性,並允許次類別修改行為。但相對來說就必須依賴超類別中的方法實踐,因為那些實踐屬於演算法中的一部分。 ### 重點 樣板方法定義了演算法的步驟,由次類別實踐這些步驟。 樣板方法模式能夠讓我們達到程式碼再用性的目的。 樣板方法的抽象類別可以定義具象方法、抽象方法、以及掛勾。 所有抽象方法必須在次類別中被實踐。 掛勾是一種方法,他不做是,或者只做預設的事情,次類別可以選擇要不要去推翻他。 為了防止次類別改變樣板方法中的演算法,可以將樣板方法宣告為 FINAL。 好萊塢守則告訴舞們,將決策權放在高階模組中,以便決定如何、以及何時呼叫低階模組。 策略模式以及樣板方法模式都是用來封裝 演算法的,策略模式使用合成,樣板方法使用繼承。 工廠方法是樣板方法的一種特殊版本。? ## oo 守則 將變動的部分封裝起來 多用合成,少用繼承 針對介面寫程式,部是針對實踐寫程式 努力鬆綁物件之間的緊密度 類別應該開放,以便擴充;應該關閉,禁止修改 (開放封閉原則) 依賴抽象,不要依賴具象類別 (依賴倒轉原則) 只告訴你的朋友 (尼米特法則) 別找我,我會找你 (好萊塢守則) 首字母 指代 概念 S 單一功能原則 認為物件應該僅具有一種單一功能的概念。 O 開閉原則 認為「軟體體應該是對於擴充開放的,但是對於修改封閉的」的概念。 L 里氏替換原則 認為「程式中的物件應該是可以在不改變程式正確性的前提下被它的子類所替換的」的概念。 參考契約式設計。 I 介面隔離原則 認為「多個特定客戶端介面要好於一個寬泛用途的介面」[5] 的概念。 D 依賴反轉原則 認為一個方法應該遵從「依賴於抽象而不是一個實例」[5] 的概念。 依賴注入是該原則的一種實現方式。 -------------- # FACADE 表象模式 表象模式提供了一個統一的界面,用來存取次系統中的一群界面,表象定義了一個較高層次的介面,讓次系統更容易使用。 --- #### **"認識極少化"** 守則(Least Knowledge):只和你的密友談話。 當你正在設計一個系統,不管他是任何物件,都要注意它所互動的類別有哪些,並注意他和這些類別如何互動。 這個守則希望我們在設計中不要讓太多類別綑綁再一起,免得修改系統中一部分,會影響到其他部分。如果許多類別之間互相依賴,就會變成一個易碎的系統,需要花許多成本維護,也因為太過於複雜而不容易被理解。 Law of Demeter 同義 ### 如何不要得到太多朋友以極有影響力的物件 守則告訴我們,以某個物件而言,此物件的方法定義內,只應該引用物件的某些方法,這些方法必須屬於: - 該物件本身 - 被當作方法的參數而傳遞進來的物件 - 此方法所建立或實體化的任何物件 - 物件的任何元件 (把 **"元件"** 想像成是被實體變數所參考到的任何物件,換句話說,把這想像成是 **有一個(HAS-A)** 的關係。) **如果某物件是從其他方法中所傳回來的,不要呼叫該物件的方法** 遵守守則: ```java // 透過在氣象站中加入取得溫度方法,減少所依賴的類別數目 public float getTemp() { return station.getTemperature(); } ``` 不遵守守則 ```java // 從氣象站取得溫度計物件,接著又從溫度計物件取得溫度 public float getTemp() { Thermometer thermometer = station.getThermometer(); return thermometer.getTemperature(); } ``` 缺點: 雖然這個守則減少了物件之間的依賴程度,減少了軟體的維護成本但採用這守則也會導致更多的 **包裝** 類別被製造出來,以處理和其他物件的溝通。這可能導致複雜度以及開發時間的增加,並降低執行期的效率。 實踐一個表象,需要將次系統中的元件合盛進表象中,然後將工作轉由元件執行。 當需要簡化並統一一個很大的介面,或者一群複雜的介面,使用表象。 轉接器將一個或多個物件包裝起來以改變並提供符合使用者的介面。 裝飾者將一個物件包裝起來以增加新的行為和責任。 表象將一群物件包裝起來,以簡化其介面。 轉接器將一個介面轉換成另一個介面。 裝飾者不改變介面,但加入責任。 表象讓介面簡化。 --- # 讀書會重點摘要 ## 範本方法模式 ### 定義: 範本方法模式,定義一個操作中的演算法的骨架,而將依些步驟延遲到子類別中。範本方法使的子類別可以不改變一個演算的結構即可重定義該演算法中的某些特定步驟。 p.140 當我們要完成在某一細節層次醫治的一個過程或一系列步驟,但其個別步驟在更詳細的層次上的實現可能不同時,我們通常考慮用範本模式來處理。 -> 考券相同,作答內容不同 p.145 範本方法模式是透過把不變的行為搬移到超類別,去除子類別中重複的程式碼來展現他的優勢。 -> 何時要用?當遇到由揖謝列步驟構成過程需要執行。這個過程從高層次上看是相同的,但有些步驟的實現可能不同。這時候我們通常就應該考慮使用範本方法模式了。 p.145 當不變的合可變的行為在方法的子類別實現中混合再一起的時候,不變的行為就會在子類別中重複出現。我們透過範本方法模式把這些行為搬移到單一的地方,這樣就幫助子類別擺脫重複的不變行為的糾纏。 --- 比較: 樣板:次類別決定如何實踐演算法中的某些步驟 策略:將可互換的行為封裝起來,然後使用委託的方式決定要採取哪一個行為 工廠:由次類別決定實體化哪個具象類別 樣板方法 V.S 策略模式 策略模式定義一個演算法家族,並讓這些演算法可以互換。正因為每一個演算法都被封裝起來,所以客戶可以輕易地使用不同的演算法。 樣板模式定義一個演算法的大鋼,而由次類別中定義其中某些(抽象)步驟的內容,這麼一來,次類別可以有不同的實踐細節,但是演算法的季夠依然維持不變。 策略模式必須放棄對演算法的控制, 但策略模式的依賴度較低,透過物件合成的方式,使用者可以在執行期透過使用不同的策略物件改變演算法。 樣板模式在超類別中提供了一個基礎的方法,達到程式碼的再用性,並允許次類別修改行為。但相對來說就必須依賴超類別中的方法實踐,因為那些實踐屬於演算法中的一部分。 選擇商家版本 ## 外觀模式 ### 定義: 外觀模式,為子系統中的一組介面提供一個一致的介面,此模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。 p.163 完美的體現了依賴倒轉原則和迪米特法則的思想,是非常常用的模式之一。 -> 不直接依賴低階模組,依賴介面; 對底層的實現不用知道,符合最小知識 何時使用外觀模式? p.164 1. 首先,在設計初期階段,應該要有義式的將不同的兩個層分離,層與層之間建立外觀 Facade,這樣可以為複雜的子系統提供一個簡單的介面。 2. 其次,在開發階段,子系統往往因為不斷的重夠演化而變得愈來越複雜,大多數的模式使用時也會產生很多很小的類別,這原本是好事,但也給外部調用他們的用戶程式帶來了使用上得困難,** 增加外觀 Facade ** 可以提供一個簡單的介面,減少他們之間的依賴。 3. 第三,在維護一個遺留的大型系統時,可能這個系統已經非常難以維護和擴展了,但是因為它包含非常重要的功能,新的需求開發必須要依賴他。 此時用外觀模式 Facade 也是非常合適的。你可以為新系統開發一個外觀 Facade 類別,來提供設計粗糙或高度複雜的遺留程式碼比較清晰簡單的介面,讓新系統與 Facade 物件互動,Facade 與遺留程式碼互動所有的複雜工作。 Q: Waca Facade 都只是單純拿來做倒轉,但並沒有再做其他事情,這樣有其他更適合的方法嗎? 還是這也是 Facade 的其中一種用法? [封裝與迪米特法則](https://www.ithome.com.tw/voice/98670)

    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