{"id":22,"date":"2012-07-20T14:58:49","date_gmt":"2012-07-20T13:58:49","guid":{"rendered":"http:\/\/oprsteny.cz\/?p=22"},"modified":"2012-07-20T15:05:24","modified_gmt":"2012-07-20T14:05:24","slug":"design-patterns-abstract-factory","status":"publish","type":"post","link":"https:\/\/oprsteny.cz\/?p=22","title":{"rendered":"Design Patterns &#8211; Abstract Factory"},"content":{"rendered":"<h1>Intent<\/h1>\n<ul>\n<li>Provide an interface for creating families of related or dependent objects without specifying their concrete\u00a0classes.<\/li>\n<li>A hierarchy that encapsulates: many possible \u201cplatforms\u201d, and the construction of a suite of\u00a0\u201cproducts\u201d.<\/li>\n<li>The\u00a0<code>new<\/code>\u00a0operator considered\u00a0harmful.<!--more--><\/li>\n<\/ul>\n<h1>Problem<\/h1>\n<p>If an application is to be portable, it needs to encapsulate platform dependencies. These \u201cplatforms\u201d might include: windowing system, operating system, database, etc. Too often, this encapsulatation is not engineered in advance, and lots of\u00a0<code>#ifdef<\/code>\u00a0case statements with options for all currently supported platforms begin to procreate like rabbits throughout the\u00a0code.<\/p>\n<h1>Discussion<\/h1>\n<p>Provide a level of indirection that abstracts the creation of families of related or dependent objects without directly specifying their concrete classes. The \u201cfactory\u201d object has the responsibility for providing creation services for the entire platform family. Clients never create platform objects directly, they ask the factory to do that for\u00a0them.<\/p>\n<p>This mechanism makes exchanging product families easy because the specific class of the factory object appears only once in the application &#8211; where it is instantiated. The application can wholesale replace the entire family of products simply by instantiating a different concrete instance of the abstract\u00a0factory.<\/p>\n<p>Because the service provided by the factory object is so pervasive, it is routinely implemented as a\u00a0Singleton.<\/p>\n<h1>Structure<\/h1>\n<p>The Abstract Factory defines a Factory Method per product. Each Factory Method encapsulates the\u00a0<code>new<\/code>\u00a0operator and the concrete, platform-specific, product classes. Each \u201cplatform\u201d is then modeled with a Factory derived\u00a0class.<\/p>\n<div><img decoding=\"async\" src=\"http:\/\/sourcemaking.com\/files\/sm\/images\/patterns\/Abstract_Factory.gif\" alt=\"Scheme of Abstract Factory\" \/><\/div>\n<h1>Example<\/h1>\n<p>The purpose of the Abstract Factory is to provide an interface for creating families of related objects, without specifying concrete classes. This pattern is found in the sheet metal stamping equipment used in the manufacture of Japanese automobiles. The stamping equipment is an Abstract Factory which creates auto body parts. The same machinery is used to stamp right hand doors, left hand doors, right front fenders, left front fenders, hoods, etc. for different models of cars. Through the use of rollers to change the stamping dies, the concrete classes produced by the machinery can be changed within three\u00a0minutes.<\/p>\n<div><img decoding=\"async\" src=\"http:\/\/sourcemaking.com\/files\/sm\/images\/patterns\/Abstract_Factory_example1.gif\" alt=\"Example of Abstract Factory\" \/><\/div>\n<h1>Check\u00a0list<\/h1>\n<ol>\n<li>Decide if \u201cplatform independence\u201d and creation services are the current source of\u00a0pain.<\/li>\n<li>Map out a matrix of \u201cplatforms\u201d versus\u00a0\u201cproducts\u201d.<\/li>\n<li>Define a factory interface that consists of a factory method per\u00a0product.<\/li>\n<li>Define a factory derived class for each platform that encapsulates all references to the\u00a0<code>new<\/code>\u00a0operator.<\/li>\n<li>The client should retire all references to\u00a0<code>new<\/code>, and use the factory methods to create the product\u00a0objects.<\/li>\n<\/ol>\n<h1>Rules of\u00a0thumb<\/h1>\n<ul>\n<li>Sometimes creational patterns are competitors: there are cases when either Prototype or Abstract Factory could be used profitably. At other times they are complementary: Abstract Factory might store a set of Prototypes from which to clone and return product objects, Builder can use one of the other patterns to implement which components get built. Abstract Factory, Builder, and Prototype can use Singleton in their\u00a0implementation.<\/li>\n<li>Abstract Factory, Builder, and Prototype define a factory object that\u2019s responsible for knowing and creating the class of product objects, and make it a parameter of the system. Abstract Factory has the factory object producing objects of several classes. Builder has the factory object building a complex product incrementally using a correspondingly complex protocol. Prototype has the factory object (aka prototype) building a product by copying a prototype\u00a0object.<\/li>\n<li>Abstract Factory classes are often implemented with Factory Methods, but they can also be implemented using\u00a0Prototype.<\/li>\n<li>Abstract Factory can be used as an alternative to Facade to hide platform-specific\u00a0classes.<\/li>\n<li>Builder focuses on constructing a complex object step by step. Abstract Factory emphasizes a family of product objects (either simple or complex). Builder returns the product as a final step, but as far as the Abstract Factory is concerned, the product gets returned\u00a0immediately.<\/li>\n<li>Often, designs start out using Factory Method (less complicated, more customizable, subclasses proliferate) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, more complex) as the designer discovers where more flexibility is\u00a0needed.<\/li>\n<\/ul>\n<h1>Java example<\/h1>\n<pre lang=\"java\">public abstract class CPU\r\n{\r\n  ...\r\n} \/\/ class CPU\r\n\r\nclass EmberCPU extends CPU\r\n{\r\n  ...\r\n} \/\/ class EmberCPU\r\n\r\nclass EmberToolkit extends ArchitectureToolkit\r\n{\r\n  public CPU createCPU()\r\n  {\r\n    return new EmberCPU();\r\n  } \/\/ createCPU()\r\n\r\n  public MMU createMMU()\r\n  {\r\n    return new EmberMMU();\r\n  } \/\/ createMMU()\r\n  ...\r\n} \/\/ class EmberFactory\r\n\r\npublic abstract class ArchitectureToolkit\r\n{\r\n  private static final EmberToolkit emberToolkit = new EmberToolkit();\r\n  private static final EnginolaToolkit enginolaToolkit = new EnginolaToolkit();\r\n  ...\r\n\r\n  \/\/ Returns a concrete factory object that is an instance of the\r\n  \/\/ concrete factory class appropriate for the given architecture.\r\n  static final ArchitectureToolkit getFactory(int architecture)\r\n  {\r\n    switch (architecture)\r\n    {\r\n      case ENGINOLA:\r\n        return enginolaToolkit;\r\n\r\n      case EMBER:\r\n        return emberToolkit;\r\n        ...\r\n    } \/\/ switch\r\n    String errMsg = Integer.toString(architecture);\r\n    throw new IllegalArgumentException(errMsg);\r\n  } \/\/ getFactory()\r\n\r\n  public abstract CPU createCPU();\r\n  public abstract MMU createMMU();\r\n  ...\r\n} \/\/ AbstractFactory\r\n\r\npublic class Client\r\n{\r\n  public void doIt()\r\n  {\r\n    AbstractFactory af;\r\n    af = AbstractFactory.getFactory(AbstractFactory.EMBER);\r\n    CPU cpu = af.createCPU();\r\n    ...\r\n  } \/\/ doIt\r\n} \/\/ class Client<\/pre>\n<h1>C# example<\/h1>\n<pre lang=\"csharp\">using System;\r\n\r\n  class MainApp\r\n  {\r\n    public static void Main()\r\n    {\r\n      \/\/ Abstract factory #1 \r\n      AbstractFactory factory1 = new ConcreteFactory1();\r\n      Client c1 = new Client(factory1);\r\n      c1.Run();\r\n\r\n      \/\/ Abstract factory #2 \r\n      AbstractFactory factory2 = new ConcreteFactory2();\r\n      Client c2 = new Client(factory2);\r\n      c2.Run();\r\n\r\n      \/\/ Wait for user input \r\n      Console.Read();\r\n    }\r\n  }\r\n\r\n  \/\/ \"AbstractFactory\" \r\n  abstract class AbstractFactory\r\n  {\r\n    public abstract AbstractProductA CreateProductA();\r\n    public abstract AbstractProductB CreateProductB();\r\n  }\r\n\r\n  \/\/ \"ConcreteFactory1\" \r\n  class ConcreteFactory1 : AbstractFactory\r\n  {\r\n    public override AbstractProductA CreateProductA()\r\n    {\r\n      return new ProductA1();\r\n    }\r\n    public override AbstractProductB CreateProductB()\r\n    {\r\n      return new ProductB1();\r\n    }\r\n  }\r\n\r\n  \/\/ \"ConcreteFactory2\" \r\n  class ConcreteFactory2 : AbstractFactory\r\n  {\r\n    public override AbstractProductA CreateProductA()\r\n    {\r\n      return new ProductA2();\r\n    }\r\n    public override AbstractProductB CreateProductB()\r\n    {\r\n      return new ProductB2();\r\n    }\r\n  }\r\n\r\n  \/\/ \"AbstractProductA\" \r\n  abstract class AbstractProductA\r\n  {\r\n  }\r\n\r\n  \/\/ \"AbstractProductB\" \r\n  abstract class AbstractProductB\r\n  {\r\n    public abstract void Interact(AbstractProductA a);\r\n  }\r\n\r\n  \/\/ \"ProductA1\" \r\n  class ProductA1 : AbstractProductA\r\n  {\r\n  }\r\n\r\n  \/\/ \"ProductB1\" \r\n  class ProductB1 : AbstractProductB\r\n  {\r\n    public override void Interact(AbstractProductA a)\r\n    {\r\n      Console.WriteLine(this.GetType().Name + \" interacts with \" + a.GetType().Name);\r\n    }\r\n  }\r\n\r\n  \/\/ \"ProductA2\" \r\n  class ProductA2 : AbstractProductA\r\n  {\r\n  }\r\n\r\n  \/\/ \"ProductB2\" \r\n  class ProductB2 : AbstractProductB\r\n  {\r\n    public override void Interact(AbstractProductA a)\r\n    {\r\n      Console.WriteLine(this.GetType().Name + \" interacts with \" + a.GetType().Name);\r\n    }\r\n  }\r\n\r\n  \/\/ \"Client\" - the interaction environment of the products \r\n  class Client\r\n  {\r\n    private AbstractProductA AbstractProductA;\r\n    private AbstractProductB AbstractProductB;\r\n\r\n    \/\/ Constructor \r\n    public Client(AbstractFactory factory)\r\n    {\r\n      AbstractProductB = factory.CreateProductB();\r\n      AbstractProductA = factory.CreateProductA();\r\n    }\r\n\r\n    public void Run()\r\n    {\r\n      AbstractProductB.Interact(AbstractProductA);\r\n    }\r\n  }<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Intent Provide an interface for creating families of related or dependent objects without specifying their concrete\u00a0classes. A hierarchy that encapsulates: many possible \u201cplatforms\u201d, and the construction of a suite of\u00a0\u201cproducts\u201d. The\u00a0new\u00a0operator considered\u00a0harmful.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[6,4],"tags":[],"class_list":["post-22","post","type-post","status-publish","format-standard","hentry","category-creational-patterns","category-design-patterns"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p3nYbe-m","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/oprsteny.cz\/index.php?rest_route=\/wp\/v2\/posts\/22","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/oprsteny.cz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/oprsteny.cz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/oprsteny.cz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/oprsteny.cz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=22"}],"version-history":[{"count":5,"href":"https:\/\/oprsteny.cz\/index.php?rest_route=\/wp\/v2\/posts\/22\/revisions"}],"predecessor-version":[{"id":112,"href":"https:\/\/oprsteny.cz\/index.php?rest_route=\/wp\/v2\/posts\/22\/revisions\/112"}],"wp:attachment":[{"href":"https:\/\/oprsteny.cz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=22"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oprsteny.cz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=22"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oprsteny.cz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=22"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}