/

Tech-study-notes 0.2.0

Creational patterns

Creational patterns provide flexibility in what gets created, who creates it, how it’s created, and when. They abstract the instantiation process, making systems independent of how objects are created, composed, and represented.


Singleton

Ensure a class has only one instance and provide a global point of access to it.

Problem

Solution

All implementations of the Singleton have these two steps in common:

Singleton structure

Drawbacks


Prototype

Lets you copy existing objects without making your code dependent on their classes.

Problem

Copying an object by creating a new instance and manually copying its fields seems straightforward, but it has limitations. Private fields may not be accessible, making a full copy impossible from outside the object. In addition, this approach tightly couples the code to a concrete class, which is problematic when only an interface is known rather than the actual implementation.

Solution

The pattern delegates the cloning process to the actual objects that are being cloned, by declaring a common interface for objects that support cloning (usually such interface contains just a single clone method). This avoids coupling code to the class of that object, i.e. your code shouldn’t depend on the concrete classes of objects that you need to copy.

An object that supports cloning is called a prototype. Its clone method creates an object of the current class and carries over all of the field values of the old object into the new one.

Prototype structure

When your objects have dozens of fields and hundreds of possible configurations, cloning them might serve as an alternative to subclassing: instead of having multiple dummy subclasses that match some configuration, the client can simply look for an appropriate prototype and clone it.

Also, prototyping can avoid creation of new objects, which sometimes can be expensive (complex initialization, database queries, network calls)

Drawbacks


Factory Method

Provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.

Problem

Imagine that you’re creating a logistics management app. You first only handle transportation by trucks, but after a while you need to incorporate sea logistics. Now most of your code is coupled to the Truck class. Adding Ships into the app would require making changes to the entire codebase (and the same happens for each new type of transportation).

Solution

The pattern suggests that you replace direct object construction calls (using the new operator) with calls to a special factory method. The objects are still created via the new operator, but it’s being called from within the factory method. Objects returned by a factory method are referred to as products.

Creator and product classes for this example:

Factory method creator classes
Factory method product classes

The client doesn’t see a difference between the actual products returned by various subclasses; it treats all the products as abstract Transport. It knows they are supposed to have the deliver method, but exactly how it works isn’t important to the client.

It’s clear that this pattern is useful when you don’t know beforehand the exact types and dependencies of the objects your code should work with, and you want to provide users with a way to extend the app’s internal components. Also, it follows Open/Closed Principle and Single Responsibility principle.

Structure

Factory method Structure

The Creator class declares the factory method that returns new product objects. nNote that the factory method doesn’t have to create new instances all the time; it can also return existing objects from a cache, an object pool, or another source.

Drawbacks


Builder

Lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code

Problem

A complex object may require many configuration options. One way to support this is to create a huge constructor with lots of optional parameters, but this quickly becomes hard to read and easy to misuse. Another way is to create many subclasses for common combinations, but that leads to a large inheritance tree that mostly exists to represent construction details.

The real issue is that object creation starts to leak into client code. The client has to know which parts are required, which order they must be configured in, and which combinations make sense.

Solution

Builder moves the construction logic into separate builder objects. Instead of passing every option to a constructor at once, the client calls a sequence of clear construction steps, such as buildWalls, buildDoor, or buildEngine.

Different builders can implement the same steps in different ways, producing different representations of the final object. For example, the same construction process could create a normal house, a stone house, or even a manual that describes how the house should be built.

When construction has a common order, a Director object can run the steps for the client. The client can still use a builder directly when it needs a custom configuration.

Structure

The pattern typically has these roles:

  1. Builder Declares the construction steps common to all builders.

  2. Concrete Builders Provide specific implementations of the construction steps and keep the result being assembled.

  3. Product The complex object produced by a builder. Products from different builders do not always need to share the same interface.

  4. Director Defines reusable construction sequences, but is optional.

  5. Client Chooses a builder, optionally passes it to a director, and gets the finished product from the builder.

Drawbacks


Abstract Factory

Lets you produce families of related objects without specifying their concrete classes

Problem

Imagine an app that supports several UI themes. Each theme has related products, such as buttons, checkboxes, and menus. A light button should be used with a light checkbox; a dark button should be used with a dark checkbox.

If the client creates concrete classes directly, the code becomes full of checks such as “if dark theme, create dark button”. It also becomes easy to accidentally mix products from different families.

Solution

Abstract Factory defines an interface for creating each kind of product in a family. Concrete factories implement that interface and create products that belong together.

The client receives a factory object and uses it to create products. It does not know whether it is working with the light, dark, Windows, macOS, or any other family. It only works with abstract product interfaces, so the whole family can be switched by passing a different factory.

This is useful when a system must stay independent from concrete product classes and when products are designed to be used together.

Structure

The pattern typically has these roles:

  1. Abstract Factory Declares methods for creating each abstract product.

  2. Concrete Factories Create products that belong to one specific family or variant.

  3. Abstract Products Declare interfaces for each kind of product in the family.

  4. Concrete Products Implement product interfaces for a specific family.

  5. Client Works only with abstract factories and abstract products, so it stays decoupled from concrete classes.

Drawbacks