Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Creational Design Patterns

Overview creational design patterns

  • Login to see the comments

Creational Design Patterns

  1. 1. Creational Patterns 20170125 Taka Wang
  2. 2. “In software engineering, a software design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. It is not a finished design that can be transformed directly into source or machine code. It is a description or template for how to solve a problem that can be used in many different situations.”
  3. 3. Combo?
  4. 4. Keep it simple (KISS)
  5. 5. The Beginner uses patterns everywhere
  6. 6. The Beginner uses patterns everywhere As learning progresses, the Intermediate mind starts to see where patterns are needed and where they aren’t.
  7. 7. The Beginner uses patterns everywhere As learning progresses, the Intermediate mind starts to see where patterns are needed and where they aren’t. The Zen mind is able to see patterns where they fit naturally.
  8. 8. Scope Type of Pattern Creational Structural Behavioral Class-Level Factory Method Adapter Interpreter Template Method Object-Level Abstract Factory Builder Prototype Singleton Bridge Composite Decorate Facade Proxy Flyweight Chain of Responsibility Command Iterator Mediator Memento Observer State Strategy Visitor How relationships between classes and defined via inheritance. Established at compile time. How relationships between objects and defined via composition. Established at runtime time. How classes and objects interact and distribute responsibility. 封裝⾏行行為 Let you compose classes or objects into larger structures. Involve object instantiation and provide a way to decouple a client from the object it needs instantiate Classification
  9. 9. Principles behind the design patterns • Program to an interface, not an implementation (trying whenever is possible to do not declare variables to be instances of particular concrete class. i.e., programming to a super type) • Favor object composition (aggregation) over class inheritance (inheritance breaks encapsulation and can not be defined dynamically at run time. i.e., change behavior at runtime. • Delegation (each request to an object called is forwarded to another object)
  10. 10. Abstract Factory Pattern
  11. 11. Abstract Factory Pattern • Intent: provide an interface for creating families of related or dependent objects without specifying their concrete classes. • Example: • User interfaces for different operating system. • Select device drivers according to machine capacity. • 從資料庫抓出 Shape,顯⽰示並且印出這些形狀狀 • 有兩兩種 display resolution, print resolution
  12. 12. Different Drivers for Different Machines • 所以考慮有兩兩種 Family,低解析度與⾼高解析度。 • A Low-resolution (Low-Capacity) family: LRDD and LRPD • A High-resolution (High-Capacity) family: HRDD and HRPD For Driver In a Low-Capacity Machine, Use In a High-Capacity Machine, Use Display LRDD
 Low-resolution display driver HRDD
 High-resolution display driver Print LRPD
 Low-resolution print driver HRPD
 High-resolution print driver
  13. 13. Alternative 1: Switch class ApControl { ... public void doDraw() { switch (RESOLUTION) { case LOW: // use lrdd case HIGH: // use hrdd } } public void doPrint() { switch (RESOLUTION) { case LOW: // use lrpd case HIGH: // use hrpd } } }
  14. 14. Alternative 1: Switch • Tight Coupling: 如果要增加⼀一個新的 resolution,要同時改兩兩個地⽅方。
 • Weak Cohesion: 有兩兩個不相關的任務 doDraw 與 doPrint。它們都必須建立 形狀狀,也必須操⼼心使⽤用哪種 Driver。 class ApControl { ... public void doDraw() { switch (RESOLUTION) { case LOW: // use lrdd case HIGH: // use hrdd } } public void doPrint() { switch (RESOLUTION) { case LOW: // use lrpd case HIGH: // use hrpd } } }
  15. 15. Switches may indicate a need for abstraction 使⽤用 Switch 時,⾃自⼰己要提醒⾃自⼰己: • 可能需要使⽤用 polymorphism • 可能錯放 responsibilities • switch case 不總是惡惡魔,但⼀一次要同時改多處的 switch 是有點危險 的設計。
  16. 16. Alternative 2: 
 Handling variation with inheritance {{abstract}} ApControl - DisplayDriver() - PrintDriver() LowResApControl - HighResApControl - constructor instantiate ⾼高解析度 drivers,並將它們指派給 DisplayDriver 與 PrintDriver constructor instantiate 低解析度 drivers,並將它們指派給 DisplayDriver 與 PrintDriver
  17. 17. 可能的問題多多 • 組合爆炸:新組合會衍⽣生更更多的 ApControl Concrete Classes • 涵義不清:新⽣生成的 Class 可能很難解釋⽬目的 (混亂的概念念) • 違反 Favor aggregation (composition)
  18. 18. Alternative 3: Replace Switches with abstraction (封裝變化) {{abstract}} DisplayDriver - LRDD - HRDD - {{abstract}} PrintDriver - LRPD - HRPD - class ApControl { ... public void doDraw() { switch (RESOLUTION) { case LOW: // use lrdd case HIGH: // use hrdd } } public void doPrint() { switch (RESOLUTION) { case LOW: // use lrpd case HIGH: // use hrpd } } }
  19. 19. Polymorphism {{abstract}} DisplayDriver + draw() LRDD - HRDD - {{abstract}} PrintDriver + print() LRPD - HRPD - ApControl - doDraw() - doPrint() class ApControl { ... public void doDraw() { ... myDisplayDriver.draw() } public void doPrint() { ... myPrintDriver.print() } } program to an interface,
 not an implementation
  20. 20. We Got a Problem • How do we create the appropriate object? • 讓 ApControl 處理理 • 將來來會有維護上的困難,需要⼀一直修改。 • 違反 SRP。只管怎麼⽤用就好 • 讓專⾨門的⼯工廠來來處理理 - 專⾨門負責挑選適合的 Driver => ResFactory
  21. 21. Responsibilities and Cohesion • 從 ApControl ⾓角度來來看,knowing how to work with the appropriate objects • 從 Factory ⾓角度來來看,keeping track of which drivers to use, i.e., decide which objects are appropriate. • Factory 負責產⽣生(初始化)適合的 Driver • ApControl 負責使⽤用它們
  22. 22. 避免 Switch 的⽅方法之⼀一 {{abstract}} ResolutionFactory + GetDispDriver() + GetPrintDriver() LowResFact - HighResFact - abstract class ResFactory { abstract public DisplayDriver getDispDrvr(); abstract public PrintDriver getPrtDrvr(); } class LowResFact : ResFactory { public DisplayDriver getDispDrvr() { return new LRDD(); } public PrintDriver getPrtDrvr() { return new LRPD(); } } class HighResFact : ResFactory { public DisplayDriver getDispDrvr() { return new HRDD(); } public PrintDriver getPrtDrvr() { return new HRPD(); } } 注意: 多個 method
  23. 23. Key Features Intent You want to have families or sets of objects for particular clients (or cases). Problem Families of related objets need to be instantiated. Solution Coordinates the creation of families of objects. Gives a way to take the rules of how to perform the 
 instantiation out of the client object that is using theses created objects. Participants and 
 Collaborators The AbstractFactory defines the interface for how to create each member of the family of objects 
 required. Typically, each family is created by having its own unique ConcreteFactory. Consequences The pattern isolates the rules of which objects to use from the logic of how to use theses objects. Implementation Define an abstract class that specifies which objects are to be made. Then implement one concrete 
 class for each family. Tables or files can also be used to accomplish the same thing. configuration or lookup table
  24. 24. Generic Structure
  25. 25. C# Example public class DatabaseAgentFactory : IAgentFactory { public IAgentA CreateAgentA() { return new AgentA_Database(); } public IAgentB CreateAgentB() { return new AgentB_Database(); } } public class XMLAgentFactory : IAgentFactory { public IAgentA CreateAgentA() { return new AgentA_Xml(); } public IAgentB CreateAgentB() { return new AgentB_Xml(); } } public interface IAgentFactory { IAgentA CreateAgentA(); IAgentB CreateAgentB(); } public class AgentB_Database : IAgentB { internal AgentB_Database() { /* Construction here */} // IAgentB method implementations } public class AgentA_Database : IAgentA { internal AgentA_Database() { /* Construction here */} // IAgentA method implementations } public class AgentB_Xml : IAgentB { internal AgentB_Xml() { /* Construction here */} // IAgentB method implementations } public class AgentA_Xml : IAgentA { internal AgentA_Xml() { /* Construction here */} // IAgentA method implementations } public interface IAgentB { // Add some methods here! } public interface IAgentA { // Add some methods here! }
  26. 26. Check List • Map out a matrix of "platforms" versus "products". • Define a factory interface that consists of a factory method per product. (abstract factory 是由 factory method 組成的) • Define a factory derived class for each platform that encapsulates all references to the new operator. • The client should retire all references to new, and use the factory methods to create the product objects. (⽤用⼯工廠取代 new,封裝 instantiation)
  27. 27. Factory Method
  28. 28. Key Features Intent Define an interface for creating an object, but let subclasses decide which class to instantiate. Defer 
 instantiation to subclasses. Problem A class needs to instantiate a derivation of another class, but doesn’t know which one (不知道具體的產 品是哪⼀一種). Factory Method allows a derived class to make the decision. Solution A derived class makes the decision on which (product) class to instantiate and how to instantiate it. Participants and 
 Collaborators AbstractProduct is the interface for the type of object that the Factory Method creates. 
 AbstractCreator is the interface that defines the Factory Method. Consequences Clients will need to subclass the Creator class to make a particular ConcreteProduct. Implementation Use a method in the abstract class that is abstract. The abstract class’ code to this method when it needs to instantiate a contained object but does not know which particular object it needs. 建議參參考之前⼩小學堂投影片
  29. 29. Generic Structure 多個 Factory method,效果跟 abstract factory 類似 1. 繼承 2. 通常 override
  30. 30. C# Sample abstract class Creator { public abstract Product FactoryMethod(); } class ConcreteProductB : Product { } class ConcreteProductA : Product { } abstract class Product { } class MainApp { static void Main() { // An array of creators Creator[] creators = new Creator[2]; creators[0] = new ConcreteCreatorA(); creators[1] = new ConcreteCreatorB(); // Iterate over creators and create products foreach (Creator creator in creators) { Product product = creator.FactoryMethod(); Console.WriteLine("Created {0}", product.GetType().Name); } // Wait for user Console.ReadKey(); } } class ConcreteCreatorB : Creator { public override Product FactoryMethod() { return new ConcreteProductB(); } } class ConcreteCreatorA : Creator { public override Product FactoryMethod() { return new ConcreteProductA(); } }
  31. 31. Sequence Diagram
  32. 32. Check List • 在 Factory Pattern 中,Client 不需要知道具體產品類的類名,但需要知道所 對應的⼯工廠,concrete 的 product 由 concrete factory 創建 (可透過 configuration 或 database 保存)。 • 設計 abstract superclass (virtual create method),讓 subclass 實作具體的 create method • 設計 Factory method 的 引數列列 (arguments)。怎樣的引數⾜足夠分辨出正確 的 concrete factory 來來產⽣生對應的物品。 • 可以考慮設計內部的 object pool,這樣可以不⽤用總是重頭產⽣生。
  33. 33. Related Patterns • Abstract Factory Pattern 通常⽤用 Factory Method 實現,但也可以⽤用 Prototype Pattern 實現。 • Factory Method: creation through inheritance. Prototype: creation through delegation • Factory Method 常被⽤用於 Template Method 中。 • 當只有⼀一個 Concrete Factory,⽽而此 Concrete Factory 中可以創建所有的 產品 objects,並且將 Factory Method 設計為 Static 時,此時 Factory Method 就退化成 Simple Factory Pattern (Static Factory)。
  34. 34. Singleton Pattern
  35. 35. You are Monopoly Designer • 你是⼤大富翁的設計者,現在要設計銀⾏行行 • 銀⾏行行主要提供四種功能: • 提款 (withdrawal) • 存款 (deposit) • 借款 (loan) • 還款 (repayment) • 你會怎麼設計這個 Bank Class?
  36. 36. ⼀一般是這樣的 • 對於系統中的某些 Class 來來說,只有⼀一個 instance 很重要 • 例例如⼀一個系統只能有⼀一個 Counter,Logger 或 ID Generator,⼤大富翁 內只能有⼀一間銀⾏行行。 • 如何保證⼀一個 Class 只有⼀一個 instance 並且這個 instance 易易於被訪 問呢? • 定義⼀一個 global instance 可以確保此 object 隨時都可以被 access, 但不能防⽌止我們 instantiate 多個此類 instance。
  37. 37. 屎蛋,你會怎麼設計 這個銀⾏行行?
  38. 38. 屎蛋,你會怎麼設計 這個銀⾏行行? 存款、提款、借款、還款, 不就這四種功能⽽而已。
 把⼈人丟進去這些公開⽅方法!
  39. 39. 屎蛋,你會怎麼設計 這個銀⾏行行? 存款、提款、借款、還款, 不就這四種功能⽽而已。
 把⼈人丟進去這些公開⽅方法! Bank … +withdrawal(player)
 +deposit(player) +loan(player)
 +repayment(player) Player - cash
 - deposit
  40. 40. 那你怎麼確保我們
 只有⼀一間銀⾏行行?
 不會被建出很多間?
  41. 41. 那你怎麼確保我們
 只有⼀一間銀⾏行行?
 不會被建出很多間? 建銀⾏行行?那是 constructor在做的事, 避免被亂建我把它設為 private 好了了
  42. 42. 那你怎麼確保我們
 只有⼀一間銀⾏行行?
 不會被建出很多間? 建銀⾏行行?那是 constructor在做的事, 避免被亂建我把它設為 private 好了了 Bank … - Bank() +withdrawal(player)
 +deposit(player) +loan(player)
 +repayment(player)
  43. 43. 現在沒有⼈人可以建銀 ⾏行行了了!!
  44. 44. 現在沒有⼈人可以建銀 ⾏行行了了!! ⼯工廠專⾨門做這件事,⼯工 廠永遠給玩家同⼀一間銀 ⾏行行,我們保存⼀一間起來來, 被調⽤用就給同⼀一個參參照
  45. 45. 現在沒有⼈人可以建銀 ⾏行行了了!! ⼯工廠專⾨門做這件事,⼯工 廠永遠給玩家同⼀一間銀 ⾏行行,我們保存⼀一間起來來, 被調⽤用就給同⼀一個參參照 Bank -self: Bank - Bank() +withdrawal(player)
 +deposit(player) +loan(player)
 +repayment(player) +GetBank(): Bank
  46. 46. 那銀⾏行行到底何時才會真 的被建出來來?
 你的self哪來來的?
  47. 47. 那銀⾏行行到底何時才會真 的被建出來來?
 你的self哪來來的? 等到有⼈人要跟⼯工廠要銀⾏行行 時,⼯工廠才產⽣生。後⾯面來來 的玩家⼯工廠就給他同⼀一間
  48. 48. 那銀⾏行行到底何時才會真 的被建出來來?
 你的self哪來來的? 這叫做 
 Lazy Instantiation
  49. 49. 現在是確保只有⼀一間了了, 但玩家要對誰使⽤用 GetBank 這個⼯工廠⽅方法? 雞⽣生蛋、蛋⽣生雞啊!
  50. 50. 現在是確保只有⼀一間了了, 但玩家要對誰使⽤用 GetBank 這個⼯工廠⽅方法? 雞⽣生蛋、蛋⽣生雞啊! 我把 GetBank ⽅方法設為 Static 不就好了了,四種⽅方 法也乾脆 Static 算了了!
  51. 51. 現在是確保只有⼀一間了了, 但玩家要對誰使⽤用 GetBank 這個⼯工廠⽅方法? 雞⽣生蛋、蛋⽣生雞啊! 我把 GetBank ⽅方法設為 Static 不就好了了,四種⽅方 法也乾脆 Static 算了了! Bank -self: Bank - Bank() +withdrawal(player)
 +deposit(player) +loan(player)
 +repayment(player) +GetBank(): Bank
  52. 52. Good Job 屎蛋
 Let’s Go!
  53. 53. Good Job 屎蛋
 Let’s Go!
  54. 54. Key Features Intent You want to have only one of an object, but there is no global object that controls the instantiation of this object. You also want to ensure that all entities are using the same instance of this object, without passing a reference to all of them. Problem Several different client objects need to refer to the same thing, and you want to ensure that you do not have more than one of them. Solution Guarantees one instance. Make the class itself responsible for keeping track of its sole instance. [GoF] Participants and 
 Collaborators Clients create an instance of the Singleton solely through the getInstance method. Consequences Clients need not concern themselves whether an instance of the Singleton exists. This can be controlled from within the Singleton. "Just-in-time initialization" or "initialization on first use"
  55. 55. Implementation • Declare the instance as a private static data member. • Provide a public static member function that encapsulate all initialization code (like a static factory). • Provides access to the instance, i.e., getInstance method. 1. Constructor 為 private,⽤用⼾戶無法透過 new 去 instantiate 它 2. 提供⼀一個⾃自⾝身的靜態私有變量量,⽤用來來保存唯⼀一實體。 3. 提供⼀一個公有的靜態⼯工廠⽅方法
  56. 56. Generic Structure & Sequence Diagram
  57. 57. Generic Structure & Sequence Diagram
  58. 58. C# Implementation using System; public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton Instance { get { if (instance == null) { instance = new Singleton(); } return instance; } } }
  59. 59. C# Implementation using System; public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton Instance { get { if (instance == null) { instance = new Singleton(); } return instance; } } } ⽋欠考慮的實作 無法確保唯⼀一性
  60. 60. C# Implementation with Lock using System; public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton Instance { get { if (instance == null) { instance = new Singleton(); } return instance; } } } lock
  61. 61. C# Implementation with Lock using System; public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton Instance { get { if (instance == null) { instance = new Singleton(); } return instance; } } } 暴暴⼒力力的鎖 形成效能的瓶頸 lock
  62. 62. Double Checked Lock if check() { // lock hint lock() { if check() { // perform your lock-safe code here } } } The idea behind this pattern is that you would want to check first, to minimize any aggressive locking, since an IF statement is less expensive than the locking. Secondly we would want to wait and acquire the exclusive lock so only one execution is inside that block at a single time. But between the first check and the acquisition of the exclusive lock there could have been another thread that did acquire the lock, therefore we would need to check again inside the lock to avoid replacing the instance with another one. http://marcio.io/2015/07/singleton-pattern-in-go/
  63. 63. Double-Check Locking Implementation using System; public sealed class Singleton { private static volatile Singleton instance; private static object syncRoot = new Object(); private Singleton() {} public static Singleton Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) instance = new Singleton(); } } return instance; } } } lock check check
  64. 64. .NET 4.0+ Implementation public class Singleton { private static readonly Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton()); public static Singleton Instance { get { return lazy.Value; } } private Singleton() { } } http://csharpindepth.com/Articles/General/Singleton.aspx Lazy<T> lambda expression 無引數
  65. 65. Check List • Define a private static attribute in the "single instance" class. • Define a public accessor function in the class. • Do "Lazy initialization" (creation on first use) in the accessor function. • Define all constructors to be protected or private. • Clients may only use the accessor functions to manipulate the Singleton (usually static functions).
  66. 66. Common Use • ⼤大部分時間幾乎不⽤用!!! • 要提供⼀一個唯⼀一的、公開的資源存取點。例例如 GPIO 或者 Printer Task Queue. • Abstract Factory, Builder and Prototype 通常⽤用 Singleton 實作 • Facade 與 State object 通常是 Singleton
  67. 67. Object Pool Pattern
  68. 68. 故事是這樣的
  69. 69. 故事是這樣的 • 有很多⼯工作要做,老闆只管跟⼈人資要⼈人丟⼯工作,不管其他的 (有⼈人沒 ⼈人,能不能..)。
  70. 70. 故事是這樣的 • 有很多⼯工作要做,老闆只管跟⼈人資要⼈人丟⼯工作,不管其他的 (有⼈人沒 ⼈人,能不能..)。 • 團隊沒⼈人,當⼯工作進來來時,⼈人資負責招募新⼈人,並把⼯工作指派給他,公 司還規定最多只能招募⼗十個⼈人。(招募是⼀一件很繁瑣的事情,有⼀一定流 程,曠⽇日廢時)。(你要養起來來放還是隨招隨募 [lazy instantiation],看情 況)。
  71. 71. 故事是這樣的 • 有很多⼯工作要做,老闆只管跟⼈人資要⼈人丟⼯工作,不管其他的 (有⼈人沒 ⼈人,能不能..)。 • 團隊沒⼈人,當⼯工作進來來時,⼈人資負責招募新⼈人,並把⼯工作指派給他,公 司還規定最多只能招募⼗十個⼈人。(招募是⼀一件很繁瑣的事情,有⼀一定流 程,曠⽇日廢時)。(你要養起來來放還是隨招隨募 [lazy instantiation],看情 況)。 • 完成⼯工作的⼈人,告訴⼈人資⼯工作完成,等待被指派新⼯工作。如果所有⼈人都 在忙,新⼯工作需要排隊,等到有空的⼈人出現再⾏行行指派。
  72. 72. 拆解問題
  73. 73. 拆解問題 1. 有很多⼯工作要做 老闆只負責跟⼈人資要⼈人丟⼯工作 (SRP) client object pool object acquire
  74. 74. 拆解問題 1. 有很多⼯工作要做 老闆只負責跟⼈人資要⼈人丟⼯工作 (SRP) client object pool object acquire 2. 團隊沒⼈人,當⼯工作進來來時,⼈人資 負責招募新⼈人,並把⼯工作指派給他, 規定最多只能招募⼗十⼈人。(招募是⼀一 件很繁瑣的事情) Lazy instantiate
  75. 75. 拆解問題 1. 有很多⼯工作要做 老闆只負責跟⼈人資要⼈人丟⼯工作 (SRP) client object pool object acquire 3. 完成的⼈人,告訴⼈人資⼯工作完成,等 待新⼯工作。如果所有⼈人都在忙,新⼯工 作排隊等有空的⼈人出現再指派。 release 2. 團隊沒⼈人,當⼯工作進來來時,⼈人資 負責招募新⼈人,並把⼯工作指派給他, 規定最多只能招募⼗十⼈人。(招募是⼀一 件很繁瑣的事情) Lazy instantiate
  76. 76. Key Features Intent Manage the reuse of objects when it is either expensive to create an object to there is a limit on the number objects of a particular type that can be created. Problem The creation and/or management of objects must follow a well-defined set of rules. Typically these rules relate to how to make an object, how many objects can be created and how to reuse existing objects once they have finished their current tasks. Solution The Client calls ReusablePool’s acquireReusable method when it needs a Reusable object. If the pool is empty, then acquireReusable method creates a Reusable object if it can; otherwise, it waits until a Reusable object is returned to the collection. Participants and 
 Collaborators The ReusablePool manages the availability of Reusable objects for use by the Client. Client then uses instances of reusable objects for a limited amount of time. ReusablePool contains all the Reusable objects so that they can be managed in a unified way. Consequences Works best when the demand for objects is fairly consistent over time; large variations in demand can lead to performance problems. To address thus issue in the Object Pool pattern, limit the number of objects that can be created. Keeping the logic to manage the creation of instances separate from the class whose instances are being managed results in a more cohesive design.
  77. 77. Generic Structure Pool 通常搭配 Singleton 實作 acquire 可以搭配⼯工廠實作,要 不要 Lazy instantiation,看系 統的初始⼯工作量量微調。 實作容易易輕忽,變成 
 Object Cesspool ResuablePool.getInstance().acquireResuable()
  78. 78. Anti-Pattern: Object Cesspool • If objects returning to the pool are not validated, the pool can gradually fill with garbage objects, turning it into a cesspool of unusable objects. • How to identify: • Object pool does not have a “release object” method. • Overly simple “release object” method, which does not check object validity. Object Cesspool Anti-Pattern
  79. 79. Example public class ConfigWriterPool { private Queue<ConfigWriter> pool = new Queue<ConfigWriter>(); public ConfigWriter Get() { if (pool.Count > 0) { return pool.Dequeue(); } else { return BuildNewConfigWriter(); } } public void Release(ConfigWriter writer) { pool.Queue(writer); } } without check
  80. 80. Example public class ConfigWriterPool { private Queue<ConfigWriter> pool = new Queue<ConfigWriter>(); public ConfigWriter Get() { if (pool.Count > 0) { return pool.Dequeue(); } else { return BuildNewConfigWriter(); } } public void Release(ConfigWriter writer) { pool.Queue(writer); } } without check public class ConfigWriterPool { private Queue<ConfigWriter> pool = new Queue<ConfigWriter>(); public ConfigWriter Get() { if (pool.Count > 0) { return pool.Dequeue(); } else { return BuildNewConfigWriter(); } } public void Release(ConfigWriter writer) { if (IsReadyForUse(writer)) pool.Queue(writer); else DestroyWriter(writer); } private bool IsReadyForUse(ConfigWriter writer) { /* check that the writer is not null, open, in the correct position, etc. */ } private void DestroyWriter(ConfigWriter writer) { /* cleanup and dispose of the writer, it will not be used again */ } } drop or drop then create
  81. 81. Check List • Create ObjectPool class with private array of Objects inside • Create acquire and release methods in ObjectPool class • Prevent Object Cesspool • Make sure that your ObjectPool is Singleton
  82. 82. Note ⼈人⼒力力不是機器,以上只是舉例例,請不要照著施⼯工。 這個 Pattern 不在 GoF 中。
  83. 83. Builder Pattern
  84. 84. 你正在規劃旅遊計畫 旅館 旅館 旅館⾨門票 ⾨門票 ⾨門票活動⽤用餐 餐廳 冰上活動 ⽔水上活動 活動旅館 餐廳 ⽤用餐 第⼆二天第⼀一天 第三天 旅⾏行行計畫
  85. 85. You are Mario Stage Designer • 你是 Super Mario 的關卡設計者 • 每⼀一個關卡都有固定的元素 • 貼底圖 • 配置寶物 • 配置⼩小怪 • 配置過關魔王 • 你怎麼管理理這些 objects 的產⽣生?
  86. 86. 基本的元素 StageDesigner +選關卡 +配置關卡 Stage1 +實作貼底圖 +實作配置寶物 +實作配置⼩小怪 +實作配置過關魔王 - 關卡 1. 貼底圖 2. 配置寶物 3. 配置⼩小怪 4. 配置過關魔王 Stage2 +實作貼底圖 +實作配置寶物 +實作配置⼩小怪 +實作配置過關魔王
  87. 87. 利利⽤用 Open-Closed Principle 關卡編導 +選關卡(抽象關卡產⽣生器) +配置關卡() - 關卡產⽣生器 1. 貼底圖 2. 配置寶物 3. 配置⼩小怪 4. 配置過關魔王 關卡產⽣生器 +實作貼底圖 +實作配置寶物 +實作配置⼩小怪 +實作配置過關魔王 {{abstract}}
 抽象關卡產⽣生器 +實作貼底圖 +實作配置寶物 +實作配置⼩小怪 +實作配置過關魔王
 +取得關卡實體 關卡 Closed for modification。 使⽤用者透過”配置關卡”來來得 到關卡,不管實作。 Open for extension。 繼承 抽象產⽣生器,設計新的關 卡產⽣生器。
  88. 88. Key Features Intent Separate the construction of a complex object from its representation so that the same construction process can create different representations. Parse a complex representation, create one of several targets. Problem An application needs to create the elements of a complex aggregate. The specification for the aggregate exists on secondary storage and one of many representations needs to be built in primary storage. Solution The director encapsulates the parsing of the common input. The Builder hierarchy makes possible the polymorphic creation of many peculiar representations or targets. Participants and 
 Collaborators Builder:抽象建造者 ConcreteBuilder:具體建造者 Director:指揮者 Product:產品
  89. 89. Generic Structure
  90. 90. Sequence Diagram
  91. 91. GoF’s Diagram
  92. 92. 速食店套餐 https://sourcemaking.com/design_patterns/builder
  93. 93. C# Example class BuilderExample { public static void main(String[] args) { Waiter waiter = new Waiter(); PizzaBuilder hawaiian_pizzabuilder = new HawaiianPizzaBuilder(); PizzaBuilder spicy_pizzabuilder = new SpicyPizzaBuilder(); waiter.setPizzaBuilder(hawaiian_pizzabuilder); waiter.constructPizza(); Pizza pizza = waiter.getPizza(); } } // one kind of directors class Waiter { private PizzaBuilder pizzaBuilder; public void setPizzaBuilder(PizzaBuilder pb) { this.pizzaBuilder = pb; } public Pizza getPizza() { return this.pizzaBuilder.getPizza(); } public void constructPizza() { this.pizzaBuilder.createNewPizzaProduct(); this.pizzaBuilder.buildDough(); this.pizzaBuilder.buildSauce(); this.pizzaBuilder.buildTopping(); } } class SpicyPizzaBuilder : PizzaBuilder { public void buildDough() { pizza.setDough("pan baked"); } public void buildSauce() { pizza.setSauce("hot"); } public void buildTopping() { pizza.setTopping("pepperoni+salami"); } } class HawaiianPizzaBuilder : PizzaBuilder { public void buildDough() { pizza.setDough("cross"); } public void buildSauce() { pizza.setSauce("mild"); } public void buildTopping() { pizza.setTopping("ham+pineapple"); } } abstract class PizzaBuilder { protected Pizza pizza; public Pizza getPizza() { return this.pizza; } public void createNewPizzaProduct() { this.pizza = new Pizza(); } public abstract void buildDough(); public abstract void buildSauce(); public abstract void buildTopping(); } class Pizza { private String dough = ""; private String sauce = ""; private String topping = ""; public void setDough(String dough) { this.dough = this.dough; } public void setSauce(String sauce) { this.sauce = this.sauce; } public void setTopping(String topping) { this.topping = this.topping; } }
  94. 94. 退化的 Builder pattern Joshua Bloch Item 2: Consider a builder when faced with many constructor parameters
  95. 95. 重溫 Open-Closed Principle 關卡編導 +選關卡(抽象關卡產⽣生器) +配置關卡() - 關卡產⽣生器 關卡產⽣生器 +實作貼底圖 +實作配置寶物 +實作配置⼩小怪 +實作配置過關魔王 {{abstract}}
 抽象關卡產⽣生器 +實作貼底圖 +實作配置寶物 +實作配置⼩小怪 +實作配置過關魔王
 +取得關卡實體 關卡 Director ⽤用來來滿⾜足 Closed for modification。 關卡編導已經寫死組裝步驟。 Abstract ⽤用來來歸納相類的 ⾏行行為,⽤用來來滿⾜足 Open for extension 1. 貼底圖 2. 配置寶物 3. 配置⼩小怪 4. 配置過關魔王
  96. 96. 退化的 Builder Client Demo關卡產⽣生器 +實作貼底圖 +實作配置寶物 +實作配置⼩小怪 +取得關卡實體 Demo關卡 ⽔水下關卡產⽣生器 +實作貼底圖 +實作配置寶物 +實作配置⼩小怪 +實作配置過關魔王 +實作隱藏⼩小關卡 +取得關卡實體 + ⽔水下關卡 +沒有Director
 沒有Abstract Builder create create inner class inner class
  97. 97. 退化的 Builder Client Demo關卡產⽣生器 +實作貼底圖 +實作配置寶物 +實作配置⼩小怪 +取得關卡實體 Demo關卡 ⽔水下關卡產⽣生器 +實作貼底圖 +實作配置寶物 +實作配置⼩小怪 +實作配置過關魔王 +實作隱藏⼩小關卡 +取得關卡實體 + ⽔水下關卡 + create create inner class inner class Demo關卡 s1 = new Demo關卡() .Builder()
 .實作貼底圖() .實作配置寶物() .實作配置⼩小怪() .取得關卡實體();
  98. 98. Fluent Interface // getting an item from a table client.getItem('user-table') .setHashKey('userId', 'userA') .setRangeKey('column', '@') .execute() .then(function(data) { // data.result }) $("div:first").click(function () { $("#myDiv").css("color","red") .css("background","white") .fadeOut("slow") .fadeIn("slow") .slideDown("slow") .slideUp("slow") .slideDown("slow") .hide() .show() ; }); jQuery
  99. 99. Fluent Interface // getting an item from a table client.getItem('user-table') .setHashKey('userId', 'userA') .setRangeKey('column', '@') .execute() .then(function(data) { // data.result }) $("div:first").click(function () { $("#myDiv").css("color","red") .css("background","white") .fadeOut("slow") .fadeIn("slow") .slideDown("slow") .slideUp("slow") .slideDown("slow") .hide() .show() ; }); jQuery Benz.Builder() .withBody(BenzBody.Builder() .withColor() .withDoorCount() .build()) .withEngine(Engine.Builder() .withPower() .build()) .withWheel(Wheel.Builder() .withSize() .build()) .build(); Car Builder
  100. 100. Fluent Interface // getting an item from a table client.getItem('user-table') .setHashKey('userId', 'userA') .setRangeKey('column', '@') .execute() .then(function(data) { // data.result }) $("div:first").click(function () { $("#myDiv").css("color","red") .css("background","white") .fadeOut("slow") .fadeIn("slow") .slideDown("slow") .slideUp("slow") .slideDown("slow") .hide() .show() ; }); jQuery VisionCapture v1 = new VisionCapture
 .Builder(“HDV71”)
 .withWidth(2) .withHeight(2) .withResolution(1024) .withFrameRate(30) .withTriggerType(1) .build(); VisionCapture v2 = new VisionCapture
 .Builder(“HDV72”) .withTriggerType(2) .withFrameRate(15) .build(); Vision Capture Benz.Builder() .withBody(BenzBody.Builder() .withColor() .withDoorCount() .build()) .withEngine(Engine.Builder() .withPower() .build()) .withWheel(Wheel.Builder() .withSize() .build()) .build(); Car Builder
  101. 101. Check List • Decide if a common input and many possible representations (or outputs) is the problem at hand. • Encapsulate the parsing of the common input in a Reader class. • Define a Builder derived class for each target representation. • The client creates a Reader(Director) object and a Builder object, and registers the latter with the former. • The client asks the Reader(Director) to "construct". • The client asks the Builder to return the result.
  102. 102. Discussion • 最複雜的 Creational Pattern,彈性也最⼤大。 • Builder pattern 通常⽤用來來組裝 composition。 • 可以⽤用來來取代各種 factory。
  103. 103. Prototype Pattern
  104. 104. You are Pokenmon Designer • 你正在開發 Pokemon Go • 每種怪的產⽣生 (instantiate) 需要不少 composition,步驟複雜⼜又耗時 • 當訓練師走到特定地點時,我們希望能快速產⽣生不同等級的 波波 • 可預期這些波波只有等級不同,其他能⼒力力都完全⼀一樣
  105. 105. You are Pokenmon Designer • 你正在開發 Pokemon Go • 每種怪的產⽣生 (instantiate) 需要不少 composition,步驟複雜⼜又耗時 • 當訓練師走到特定地點時,我們希望能快速產⽣生不同等級的 波波 • 可預期這些波波只有等級不同,其他能⼒力力都完全⼀一樣
  106. 106. Key Features Intent Specifying the kind of objects to create using a prototypical instance, creating new objects by copying this prototype. Problem Application "hard wires" the class of object to create in each "new" expression. Participants and 
 Collaborators Define an interface in Abstract prototype for cloning itself. Concrete prototype implements an operation for cloning itself. Client creates a new object by asking a prototype to clone itself. Consequences It hides the concrete product classes from the client, thereby reducing the number of names clients know about. Moreover, these patterns let a client work with application-specific classes without modification. Implementation Declare an abstract base class that specifies a pure virtual "clone" method, and, maintains a dictionary of all "cloneable" concrete derived classes. Any class that needs a "polymorphic constructor" capability: derives itself from the abstract base class, registers its prototypical instance, and implements the clone() operation.
  107. 107. Generic Structure
  108. 108. Practical Structure
  109. 109. C# Example public class PrototypeRegistry { Hashtable catalog = new Hashtable(); public LoadProtos() { catalog.Add("1", new ConcretePrototype1()); catalog.Add("2", new ConcretePrototype2()); } public Prototype GetProto(string s) { if catalog.ContainsKey(s) { return hashtable[s].Clone(); } return null; } } public abstract class Prototype { public abstract Prototype Clone(); } public class ConcretePrototype1 : Prototype { public override Prototype Clone() { // Clones the concrete class. return (Prototype)this.MemberwiseClone(); } } public class ConcretePrototype2 : Prototype { public override Prototype Clone() { // Clones the concrete class. return (Prototype)this.MemberwiseClone(); } } class MainApp { static void Main() { registry = new PrototypeRegistry(); registry.LoadProtos(); Prototype[] protos = new Prototype[2]; protos[0] = registry.GetProto("1").clone(); protos[1] = registry.GetProto("2").clone(); foreach (Prototype pro in protos) { Product product = creator.FactoryMethod(); Console.WriteLine("Created {0}", pro.GetType().Name); } // Wait for user Console.ReadKey(); } }
  110. 110. Check List • Add a clone() method to the existing "product" hierarchy. • Design a registry that maintains a cache of prototypical objects. The registry could be encapsulated in a new Factory class, or in the base class of the "product" hierarchy. • Design a factory method that: may (or may not) accept arguments, finds the correct prototype object, calls clone() on that object, and returns the result. • The client replaces all references to the new operator with calls to the factory method.
  111. 111. 討論 • Prototype pattern 與 Factory pattern 接收到 User 命令之後即時⽣生產 物件的⽅方式不同,在 Prototype pattern中,我們需要先打造出物件的 原型樣版,待鑄模程序完成以後,接下來來就能夠輕易易地以此原型複製 產⽣生出全新的物件。 • Prototypes are useful when object initialization is expensive • 注意 Shallow Copy 與 Deep Copy 問題,Clone 有時候很難實作。
  112. 112. Summary
  113. 113. 回顧 • Abstract Factory Pattern: 負責⽣生產不同的產品家族。⼀一⼯工廠⼀一家族,通常⼯工廠有多個 create ⽅方法。 • Factory Method: 專職⼯工廠負責⽣生產產品。定義了了⽣生產的介⾯面,實際⽣生產的款式等到 Concrete 才決定。 • Singleton Pattern: 確保只有唯⼀一的物件,並有公開的介⾯面可以操作它。 • Double Checked Lock: multi-thread 時要注意 • Object Pool Pattern: 管理理⼀一堆珍貴的資源,通常資源⽣生成的代價頗⾼高。 • Cesspoll Anti-Pattern: 釋放 resource 時要注意。 • Builder: 麥當勞點餐的組合。類似的創建流程,不同的套餐組合。 • Prototype Pattern: 細胞分裂,⽤用 Clone 加上⼩小幅修改,加快創建的速度。
  114. 114. Take away • 了了解 Pattern 適⽤用的 Context • 不要死背 Pattern,思考背後的原則,也能得到類似的結構 • Program to an interface, not an implementation • Favor object composition (aggregation) over class inheritance • Delegation • SOLID • Pattern 不能硬套,要視情況微調 (KISS) • 試著⾃自⼰己畫出 Sequence Diagram,還有⽤用⾃自⼰己熟悉的語⾔言實作看看,配合 unit test 與 CI 練習
  115. 115. Reference • Design Patterns: Elements of Reusable Object-Oriented Software. GoF • Design Patterns Explained, 2nd. Alan Shalloway et al. • Head First Design Patterns. Eric Freeman et al. • SourceMaking • 圖說設計模式 • ⼤大話設計模式. 程傑
  116. 116. Thank you
  117. 117. Transparencies
 (for print)
  118. 118. Scope Type of Patterns Creational Structural Behavioral Class-Level Factory Method Adapter Interpreter Template Method Object-Level Abstract Factory Builder Prototype Singleton Bridge Composite Decorate Facade Proxy Flyweight Chain of Responsibility Command Iterator Mediator Memento Observer State Strategy Visitor
  119. 119. Abstract Factory
  120. 120. Factory Method
  121. 121. Singleton
  122. 122. Object Pool
  123. 123. Builder
  124. 124. Prototype

×