• Uncategorized
  • 0

[Python] Design Pattern (2)–Abstract Factory Pattern

Hits: 0

[Abstract Factory] Pattern

Also Known As:  [Abstract] Factory

intention

Abstract Factory Pattern is a creational [design pattern] that can create a series of related objects without specifying their concrete classes.

question

Suppose you are developing a furniture store simulator. Include some classes in your code to represent:

Series products and their different variants.

You’ll need to find a way to generate each furniture object individually, so that it’s consistent in style. Customers won’t be happy if they receive furniture in a different style.

A modern sofa doesn’t go well with a Victorian chair.

Also, you don’t want to modify existing code when adding new products or styles. Furniture suppliers update their catalogs very frequently, and you don’t want to change the core code every time you update.

solution

All variants of the same object must be placed in the same class hierarchy.

Each concrete factory class corresponds to a specific product variant.

Client code can call factories and product classes through the corresponding abstract interfaces. You can change the factory class passed to the client without modifying the actual client code, and you can also change the product variant that the client code receives.

The client does not need to know the specific class information of the factory it is calling.

One final note: If the client only touches the abstract interface, who creates the actual factory object? Typically, applications create concrete factory objects during the initialization phase. Before that, the application had to choose the factory class based on the configuration file or environment settings.

Abstract Factory Pattern Structure

  1. Abstract  Product is a set of distinct but related product declaration interfaces that make up a family of products.

  2. Concrete Products  are implementations of many different types of abstract products. All variants (Victorian/Modern) must implement the corresponding abstract product (Chair/Sofa).

  3. The Abstract  Factory interface declares a set of methods for creating various abstract products.

  4. Concrete  Factory Implements the construction method of the abstract factory. Each specific plant corresponds to a specific product variant and only this product variant is created.

  5. Although a concrete factory initializes a concrete product, its build method signature must return the corresponding abstract product. This way, client code that uses the factory class is not coupled to the specific product variant created by the factory. Clients  can interact with any concrete factory/product variant simply by calling the factory and product objects through the abstract interface.

The pseudo-code

The following example uses the abstract factory pattern to allow client code to create cross-platform UI elements without coupling to specific UI classes, while ensuring that the created elements match the specified operating system.

Cross-platform UI class example.

The same UI elements in a cross-platform application function similarly, but look different under different operating systems. Also, you need to make sure that UI elements are consistent with the current OS style. You definitely don’t want to display macOS controls in an application running under Windows.

The abstract factory interface declares a series of build methods that client code can call to generate different styles of UI elements. Each concrete factory corresponds to a specific operating system and is responsible for generating UI elements that conform to the style of that operating system.

It works as follows: The current operating system is detected after the application starts. Based on this information, the application creates the factory object with the class corresponding to the operating system. The rest of the code uses the factory object to create UI elements. This avoids generating elements of the wrong type.

Using this approach, client code simply calls the abstract interface without knowing the concrete factory classes and UI elements. In addition, client code also supports adding new factories or UI elements in the future.

This way, you don’t need to modify your client-side code every time you add a new variation of UI elements to your application. All you need to do is create a factory class that generates these UI elements, and then slightly modify the initial code of the application to select the appropriate factory class.

// The abstract factory interface declares a set of methods that can return different abstract products. These products belong to the same family
 // and are related on a high-level topic or concept. Products of the same series can usually be used in conjunction with each other. Series
 // Products can have multiple variants, but products of different variants cannot be used together.
interface GUIFactory is
    method createButton():Button
    method createCheckbox():Checkbox


// A specific factory can generate a family of products that belong to the same variant. Factories make sure that the products they create will work with each
 other . The concrete factory method signature returns an abstract product, but inside the method the concrete product is
 // instantiated.
class  WinFactory  implements  GUIFactory  is 
    method createButton():Button is 
        return  new WinButton()
    method createCheckbox():Checkbox is
        return new WinCheckbox()

// Each specific factory will contain a corresponding product variant.
class  MacFactory  implements  GUIFactory  is 
    method createButton():Button is 
        return  new MacButton()
    method createCheckbox():Checkbox is
        return new MacCheckbox()


// A specific product in a family of products must have a base interface. All product variants must implement this interface.
interface Button is
    method paint()

// The concrete product is created by the corresponding concrete factory.
class  WinButton  implements  Button  is 
    method paint() is 
        // Render the button according to the Windows style.

class  MacButton  implements  Button  is 
    method paint() is 
        // Render the button according to the macOS style

// This is the base interface of another product. All products can interact, but only products of the same specific variant can interact
 correctly.
interface Checkbox is
    method paint()

class  WinCheckbox  implements  Checkbox  is 
    method paint() is 
        // Render the checkbox according to the Windows style.

class  MacCheckbox  implements  Checkbox  is 
    method paint() is 
        // Render the checkbox according to the macOS style.

// Client code uses factories
 // and products only through abstract types (GUIFactory, Button, and Checkbox). This lets you pass it to client code without modifying any factory or product subclasses.
class  Application  is
    private field factory: GUIFactory
    private field button: Button
    constructor Application(factory: GUIFactory) is
        this.factory = factory
    method createUI() is
        this.button = factory.createButton()
    method paint() is
        button.paint()


// The program selects the factory type based on the current configuration or environment settings, and creates the factory at runtime (usually in the initial
 // initialization phase).
class  ApplicationConfigurator  is 
    method main() is
        config = readApplicationConfigFile()

        if (config.OS == "Windows" ) then 
            factory = new WinFactory()
         else  if (config.OS == "Mac" ) then 
            factory = new MacFactory()
         else 
            throw  new Exception( "Error! Unknown OS. " )

        Application app = new Application(factory)

Abstract factory pattern is suitable for application scenarios

If the code needs to interact with multiple related products of different series, but you do not want to build the code based on the specific classes of the product because the relevant information cannot be obtained in advance, or because of the consideration of future extensibility, in this case, you An abstract factory can be used.

An abstract factory provides you with an interface that you can use to create objects for each family of products. As long as your code creates objects through this interface, you won’t generate a product that is inconsistent with the type of product your application has generated.

  • If you have a class that is based on a set of abstract methods , and its main function becomes unclear as a result, then consider using the abstract factory pattern in this case.

  • In a well-designed program,  each class is responsible for only one thing . If a class interacts with multiple types of products, consider extracting the factory method into a separate factory class or a fully functional abstract factory class.

Method to realize

  1. Plot a matrix with different product types and product variants as dimensions.

  2. Declares abstract product interfaces for all products. Then have all concrete product classes implement these interfaces.

  3. Declare an abstract factory interface and provide a set of build methods for all abstract products in the interface.

  4. Implement a concrete factory class for each product variant.

  5. Develop initialization code in the application. The code initializes a specific concrete factory class based on the application configuration or the current environment. Then pass that factory object to all classes that need to create products.

  6. Find all direct calls to product constructors in the code and replace them with calls to the corresponding build methods in the factory object.

Advantages and disadvantages of abstract factory pattern

  • √ You can make sure that the products produced by the same factory match each other.
  • √ You can avoid the coupling of client and specific product code.
  • √Single responsibility principle . You can extract the production code to the same location, making the code easier to maintain.
  • Open and close principle . You don’t need to modify client-side code when introducing new product variants into your application.
  • × Since adopting this pattern requires introducing numerous interfaces and classes into the application, the code may be more complex than before.

Relationship to other modes

  • The Factory Method pattern  (simpler and more easily customizable by subclassing) is used in the beginning of many design efforts , and later evolved to use the Abstract FactoryPrototype , or Generator pattern  (more flexible but more complex).

  • [Generators] focus on how to generate complex objects in steps. Abstract factories are designed to produce a series of related objects. The abstract factory returns the product right away, and  the generator allows you to perform some additional construction steps before getting the product.

  • [The abstract factory pattern] is usually based on a set of factory methods , but you can also use the prototype pattern to generate methods for these classes.

  • When you only need to hide from client code how the subsystem creates objects, you can use abstract factories instead of the Facade pattern .

  • You can use abstract factories with bridge patterns . This pattern is useful when an abstraction defined by a bridge can only work with a specific implementation. In this case, the  abstract factory can encapsulate these relationships and hide their complexity from client code.

  • Abstract factoriesgenerators, and prototypes can all be implemented using the singleton pattern .

You may also like...

Leave a Reply

Your email address will not be published.