1 / 42

Creation al Design Patterns

Learn about various creational design patterns such as Factory, Abstract Factory, Prototype, Singleton, and Builder. Understand the problems they solve and how to implement them.

cfarrow
Download Presentation

Creation al Design Patterns

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Creational Design Patterns Yaodong Bi December 20, 2019

  2. Creational design patterns • Factory • Abstract Factory • Prototype • Singleton • Builder

  3. Factory • Problem • The client needs to create an object of a subclass, but it does not know the subclass until runtime. • Design Purpose • Create individual objects in situations where the constructor alone is inadequate. • Design Pattern Summary • Use methods to return required objects

  4. Factory – an example Client +useStack(Stack) stack +push() +pop() void useStack(Stack s) { while (condition) { stackn = new Stack(); //????? } } Stack = new MyStack(); useStack(s); //????? MyStack +push() +pop()

  5. Factory - structure void useProduct(Creator c) { Product p = c.factoryMethod(); // use p } …. Creator c = new ConcreteCreator(); useProduct(c); Client +useProduct() Product Creator +factoryMethod() Product factorMethod() { Return new ConcreteProduct(); } Concrete Creator +factoryMethod() Concrete Product

  6. Factory - participants • Product • defines the interface of objects the factory method creates. • ConcreteProduct • implements the Product interface. • Creator • declares the factory method, which returns an object of type Product. Creator may also define a default implementation of the factory method that returns a default ConcreteProduct object. • Creator and Product could be the same class • ConcreteCreator • overrides the factory method to return an instance of a ConcreteProduct. • Client • It depends only on Product and Creator. • Collaborations • Creator relies on its subclasses to define the factory method so that it returns an instance of the appropriate ConcreteProduct.

  7. Factory – sequence diagram Concrete Creator Client Creator Product factoryMethod() factoryMethod() constructor() Concrete Product op() op()

  8. Factory – sample code Class StackClient { void opUsingStacks(StackCreator sc) { Stack s1 = sc.createStack(); ... Stack si = sc.createStack(); ... Stack sn = sc.createStack(); } } Interface Stack { void push(Item i); Item pop(); } Interface StackCreator { Stack createStack(); } Class MyStack implements Stack { ... } Class YourStack implements Stack {} Class MyStackCreator implements StackCreator { Stack createStack() { return new MyStack(); } } Class YourStackCreator implements StackCreator { Stack createStack() { return new YourStack(); } } Class ClientDriver { void main() { StackClient c = new StackClient(); StackCreator sc = new MyStackCreator(); c.opUsingStacks(sc); sc = new YourStackCreator(); c.opUsingStacks(sc); } }

  9. Factory – comments • Factory methods are necessary for the OCP on object creation • Factory methods make the DIP more viable • Factory Method gives subclasses a hook for providing an extended version of an object • Creator could be a concrete class providing a default implementation of Product • Creator and Product could be the same class • There is an advantage of using a separate creator class for the product • The product and its creation are separate concerns • When the product is very complex, the creator can create products (even the first one) as demanded – lazy loading

  10. Abstract Factory • Design purpose • Provide an interface for creating families of related or dependent objects without specifying their concrete classes • Pattern summary • Capture family creation in a class containing a factory method for each class in the family

  11. Abstract Factory – examples • Word processor for different window systems • Word processor is designed to a set of interfaces of graphical elements • Each windows system manufactures its own set of button, windows, dialogs, etc • Each installation of the word processor is given a windows system (concrete factory) • Kitchen showroom • The program is designed to a common set of cabinets, counters, etc • Each different style of kitchen furniture provide the furniture in the style (classic, contemporary, etc) • Each individual kitchen showroom is given a style (concrete factory) • GUI themes

  12. Client Abstract Factory - structure ProductA Factory +createProductA() +createproductB() ProductA1 ProductA2 Factory1 +createProductA() +createproductB() Factory2 +createProductA() +createproductB() ProductB ProductB createProductB() { Return new ProductB1(); } ProductA createProductA() { Return new ProductA1(); } ProductB1 ProductB2

  13. Abstract Factory – Two Families Factory1 +createProductA() +createproductB() Factory2 +createProductA() +createproductB() ProductA1 ProductB1 ProductA2 ProductB2

  14. Abstract Factory - participants • ProductA and ProductB • defines the interface of a family of objects. • ProductA1, ProductB1, ProductA2, and ProductB2 • Two separate families of product implementation. • Factory • Defines the interface of the factory that returns the products • Factory1 and Factory2 • Concrete factories that can produce products of the family. • Factory1 produces ProductA1 and ProductB1, Factory2 produces ProductA2 and ProductB2 • Client • It depends only on the interfaces of the family products and the factory interface. • Collaborations • The client asks a subclass of Factory to create concrete products of ProductA and productB.

  15. Abstract Factory – Two Families Data Structures Via Array Data Structures Via List DSFactoryViaArray +createStack() +createQueue) DSFactoryViaList +createStack) +createQueue() StackViaArray QueueViaArray StackViaList QueueViaList

  16. DataStructsClient Abstract Factory - structure Stack DSFactory +createStack() +createQueue() StackViaArray StackViaList DSFactoryViaArray +createStack() +createQueue) DSFactoryViaList +createStack) +createQueue() Queue Stack createStack (){ return new StackViaArray(); } Stack createStack() { return new StackViaList(); } QueueViaArray QueueViaList Queue createQueue (){ return new QueueViaArray();} Queue createQueue (){ return new QueueViaList();}

  17. Abstract Factory – sample code Interface Stack {...} Interface Queue {...} Interface Tree {...} Class StackViaArray implements Stack {...} Class QueueViaArray implements Queue {...} Class TreeViaArray implements Tree {...} Class DSFactoryViaArray implements DSFactory { Stack createStack() { return new StackViaArray(); } Queue createQueue() { return new QueueViaArray(); } Tree createTree() { return new TreeViaArray(); } } Class DataStructsClient { DSFactory af; DataStructsClient( DSFactory af) { this.af = af; } void op() { Stack s1 = af.createStack(); Stack s2 = af.createStack(); ... Queue q = af.createQueue(); ... Tree t = af.createTree(); } } Interface DSFactory { Stack createStack(); Queue createQueue(); Tree createTree(); }

  18. Abstract Factory – sample code Class StackViaList implements Stack {...} Class QueueViaList implements Queue {...} Class TreeViaList implements Tree {...} Class DSFactoryViaList implements DSFactory { Stack createStack() { return new StackViaList(); } Queue createQueue() { return new QueueViaList(); } Tree createTree() { return new TreeViaList(); } } Class ClientDriver { void main() { // Using Array-based structures DSFactory af = new DSFactoryViaArray(); DataStructsClient dsc = new DataStructsClient(af); dsc.op(); // Using list-based structures DSFactory af2 = new DSFactoryViaList(); DataStructsClient dsc2 = new DataStructsClient(af2); dsc2.op(); } }

  19. Abstract Factory – comments • Use the Abstract Factory when a clientneeds to use one of multiple families of products • It is hard to add new types of products since adding a new product means adding a new factory method to the AbstractFactory interface and its all subclasses • When families of products are different combinations of the same set of products and/or the # of families is large, many ConcreteFactory subclasses would be needed. In this case, the Prototype pattern may be employed

  20. Prototype • Design purpose • Create a set of almost identical objects whose type is determined at runtime • Pattern summary • Assume that a prototype instance is known; clone it whenever a new instance is needed

  21. Prototype – examples • Kitchen showroom • A showroom may have all cabinets in one style, counters in a different style, etc • Instead of creating a factory for each possible combination of different furniture in different styles, each individual showroom is given a prototype of each type of furniture of a style • Each prototype can clone itself

  22. Client +anOperation() Prototype - structure Prototype +clone() +otherOperations() prototype ConcreteProduct1 +clone(); +otherOperations(); ConcreteProduct2 +cone(); +otherOperations(); Prototype p = prototype.clone(); Return a copy of itself Return a copy of itself

  23. Prototype - participants • Prototype • defines the interface (an operation) of cloning itself. • ConcreteProduct1 and ConcreteProduct2 • Concrete objects that can clone themselves. • Client • Obtain more objects by asking them to clone themselves. • Collaborations • The client asks the prototype to clone itself for a new object of the prototype.

  24. Client +anOperation() Client +anOperation() Client +anOperation() Shallow vs. deep cloning (copying) prototype ref :Prototype +clone() -Nested:ref :Nested +op() -data prototype ref :Prototype +clone() -Nested:ref :Nested +op() -data ref clone:Prototype +clone() -Nested:ref Shallow cloning prototype ref :Prototype +clone() -Nested:ref :Nested +op() -data ref clone:Prototype +clone() -Nested:ref clone:Nested +op() -data Deep cloning

  25. Shallow cloning: sample code Class Prototype implements Cloneable { private int x; private Nested ref = new Nested(); public Prototype clone() { Prototype p = new Prototype() p.x = this.x; p.ref = this.ref; return p; } } Class Nested { int data; public void op() {} } Class Client { private Prototype prototype = new Prototype(); public void op() { Prototype clone = prototype.clone(); // use clone } Shallow vs. deep cloning Deep cloning: sample code Class Prototype implements Cloneable { private int x; private Nested ref = new Nested(); public Prototype clone() { Prototype p = new Prototype() p.x = this.x; p.ref = this.ref.clone(); return p; } } Class Nested implements Cloneable { int data; public void op() {} public Nested clone() { Nested n = new Nested() n.data = this.data; return n; } } Class Client { // the same Client as for Shallow cloning }

  26. Abstract Factory – Two Families Data Structures Via Array Data Structures Via List StackViaArray Stack StackViaList QueueViaArray Queue QueueViaList

  27. Prototype – sample code Class PrototypeClient { Stack sp; Queue qp; PrototypeClient( Stack s, Queue q) { this.s = s; this.q = q; } void op() { Stack s1 = sp.clone(); Stack s2 = sp.clone(); ... Queue q1 = qp.clone(); Queue q2 = qp.clone(); } } Interface Queue { Queue clone(); ... } Interface Stack { Stack clone(); ... } Class StackViaArray implements Stack { Stack clone() { StackViaArray s = new StackViaArray(); s.attr = this.attr; return s; } ... } Class StackViaList implements Stack { Stack clone() { StackViaList s = new StackViaList(); s.attr = this.attr; return s; } ... }

  28. Prototype – sample code Class QueueViaArray implements Queue { Queue clone() { QueueViaArray s = new QueueViaArray(); s.attr = this.attr; return s; } ... } Class QueueViaList implements Queue { Queue clone() { QueueViaList s = new QueueViaList(); s.attr = this.attr; return s; } ... } Interface Queue { Queue clone(); ... } Class ClientDriver { void main() { Stack s = new StackViaArray(); Queue q = new QueueViaList(); PrototypeClient pc = new PrototypeClient(s, q); pc.op(); } }

  29. Prototype – comments • If the clone does not need to be identical as its original, a factory method may be used • Be aware of the shallow cloning problem – to the deepest level • When prototypes can be grouped in a small # of different combinations, the Abstract Factory may be suitable

  30. Singleton • Design purpose • Ensure there is exactly one instance of a class • Be able to obtain the instance from anywhere in the application • Pattern summary • Make the constructor of class private or protected, define a private static attribute of the class, define a public accessor to it.

  31. Singleton – an example • A concrete factory in the Abstract Factory pattern in most cases should have only one instance – all objects are produced by the same factory • In JGrasp (or any IDE), we want one JVM (Singleton) for all Java programs.

  32. Singleton - structure Singleton +static getInstance(); +operations() -data soleInstance <<static>> return soleInstance;

  33. Singleton - participants • Singleton • Declare all constructors private and provide only one entry for obtaining a reference to the sole instance. • Client • Clients can get to the sole instance of Singleton by asking Singleton to return a reference to it. • Collaborations • A client can only call getInstance() to get a reference to the sole instance. • A client cannot create any instance of Singleton

  34. class Singleton { // since private no client can access // this reference directly private static Singleton soleInstance = new Singleton(); private int data; // since protected, no client can // create any instance directly protected Singleton(); // the only entry for clients to get a // reference to the sole instane public static Singleton getInstance() { return soleInstance; } // other operations public void operations() { } } Singleton – sample code class Client1 { void anOperation() { // Singleton ref = new Singleton(); // illegal since Singleton() is protected Singleton ref = Singleton.getInstance(); ref.operations(); } } class Client2 { void anOperation() { Singleton ref = Singleton.getInstance(); // use ref } } NOTE: objects of Client1 and Client2 would all share the same sole instance of Singleton.

  35. Singleton – comments • Lazy loading • If the object of Singleton is complex, it may take much resource to create. We better create the object only when it is referenced – lazy loading • Change the body of getInstance() with the following if (soleInstance == null) { soleInstance = new Singleton(); } return soleInstance; • Not thread safe (Java) • Two concurrent threads could cause two instances created if executed concurrently • Solution: Make getInstance() synchronized • All static members? • Since there is only one instance, why don’t we just make all members static? • If yes, then the instance may not fit with the rest of the application: e.g., display(Employee) would not work if singleton CEO is all static

  36. Builder • Design purpose • Separate the construction of a complex object from its representation so that the same construction process can create different representations • Pattern summary • Use a builder to encapsulate the representation.

  37. Builder – an example • Language translator • Translate a Java programs to other programming languages (C++, Delphi) • The translation process is the same for all target languages – mapping “import” to something (“include” in C++) • Each target language has a builder to handle each keyword/structure

  38. Director +buildProduct() Client +madeProduct() Builder - structure Builder +buildPartA() +buildPartB() +buildPartC() director builder BuilderA +buildPartA() +buildPartB() +buildPartC() +getProductA() BuilderB +buildPartA() +buildPartB() +buildPartC() +getProductB() For (every part needed in product) if (part A) builder.buildPartA(); else if (part B) builder.buildPartB(); else if (part C) builder.buildPartC(); } ProductA ProductB

  39. Builder - participants • ProductA and ProductB • Concrete products that are created by different builders. • Director • A class that knows what steps it takes to build a product, but it does not know how each step is to be carried out or does not know how each part may be added to the final product • Builder • Defines an interface for concrete builders • BuildlerA and BuilderB • Concrete builders who know to construct each part of the product and add it to the final product • Client • A client selects a director and a concrete builder to build the product it needs. The client asks the concrete builder to return the final constructed product • Collaborations • The director knows what parts are needed for the final product and the selected concrete builder knows how to product the part and add it to the final product.

  40. Builder – sequence diagram Client Director Concrete Builder Product builder = constructor() constructor() constructor(builder) buildProduct() buildPartA() addPartA() buildPartB() addPartB() buildPartC() addPartC() getProduct()

  41. Class Product { addPartA() {} addPartB() {} addPartC() {} … } Class ConcreteBuilder implements Builder { Private: Product p; ConcreteBuilder() { p = new Product(); } buildPartA() {… p.addPartA(); … } buildPartB() {… p.addPartB(); … } buildPartC() {… p.addPartC(); … } Product getResult() { return p; } } Builder – sample code Class Director { private Builder b; Director(Builder b) {this.b = b;} void buildProduct() { for each part in Product { if (partA) b.buildPartA(); else if (partB) b.buildPartB(); else if (partC) b.buildPartC(); } } } client() { Builder b = new ConcreteBuilder(); Director d = new Director(b); d.buildProduct() FinalProduct fp = b.getResult(); }

  42. Creational design patterns • Factory • Abstract Factory • Prototype • Singleton • Builder

More Related