Design Pattern Tour: Creational Patterns

Factory

Readings:

First, I’d like to clarify the difference between all kinds of factory patterns.

  1. Simple factory: A single factory class; product is determined by the parameter passing to the factory class(or using Java reflection).
  2. Factory method: all products have their own specialized factory classes.
  3. Abstract factory method: based on factory method, but each of the factories will provide a set of methods for returning different kinds of products.
  4. Static factory method: there will be no factory class, instead, the functionality is implemented in the product class as a static function.

To sum up, Factory can work as either a class or a function. Therefore, it’s just a design idea, instead of a concrete implementation. (this works for all the design patterns)

If you are new to Factory, you will probably be wondering if there’s any difference between using it and creating an instance using a constructor. Cannot polymorphism do the same thing?

Personally speaking, I think we should find our new orientation(what we are doing): We are learning design patterns, because we want to design something good so others can use it easily. For example, we are developing a framework, and we hope our clients(developers who are using our framework) will feel comfortable using and customizing(extending) our framework.
So here comes a design principle: Open/Closed Principle, meaning our design should be open to extension, but closed to modification. In other words, we only want to add more to code, but not to modify our current code(or modify as little as possible). This should be followed by both of us and clients.

Ps. Simple factory doesn’t follow this principle, because it requires modification of the existing factory when we want to add a new product class.

Thus, our goal is that we adding new features will not influence(or influence as little as possible) the code from the client, which means the client doesn’t need to change their code, and it still works.

And Factory is designed for this goal: the client doesn’t need to know the creation of a product(because it could be quite complicated if it’s a bulky class). Instead, she can just ask the factory for that product. For instance, the client wants a computer for exploring webpages. She doesn’t care if it has a 4k screen, or if its CPU is Intel. As long as it makes her feel comfortable exploring webpages, it’s fine. So, as a factory, even if I’m changing Intel to AMD, I don’t need to tell you, and you will not notice it, because you will be still having fun surfing the Internet.

While I was learning the Factory pattern, almost all materials mentioned this pattern was good because it decoupled the code. However, I think there’s no REAL decoupling, because as long as two classes are related, they are coupled. We eliminate the coupling between the client code and the product code, but we bring in coupling between client and factory and that between factory and product.

I think decoupling is mostly achieved using abstraction (as well as Liskov Substitution Principle, LSP). Thus, I’d like to say the advantage of Factory is to hide the details of the product creation, instead of decoupling.Of course, if you insist on decoupling, I would prefer this explanation of “coupling”(https://www.zhihu.com/question/21386172/answer/54501456 ): The essence of code decoupling is that one makes some assumptions about the other one. In other words, the more one assumes, the more coupling between them. And it’s very common that one couples many others.

Also, you have to admit that product creation and product itself are two separate things(according to the Single Responsibility Principle). Then, using constructor with some default arguments or read arguments from configuration files will not be under our consideration.

Thus, with this understanding, I think it’s safe to say Factory can decouple the code. Because without Factory, the client should assume how to use both the factory and product APIs. However, with Factory, the client only needs to know product APIs(the interface of Factory method is relatively stable, so to change products, the only thing we need to do is to change the Factory class).

In conclusion, I think there are two main advantages/applications for Factory:

  1. To use Factory class to reuse cached instances instead of creating a new instance if the class is bulky. E.x. connection pool.
  2. To simplify the creation from the client side if the constructor requires many arguments. Factory class can load these arguments from configuration files, thereby separating the product and product creation and hiding the details of creation, making client code more clear. E.x. DB URL, DB username, DB password.

Builder

Readings:

I think Builder is a better choice than Factory for understanding creational patterns, because it highlights the separation of creation and product and it doesn’t bring us questions of Factory like “why not use new to create instances directly”.

Builder has two characteristics: stey-by-step(a sense of assembling) and hiding creation of complicated objects(from bulky class).As for Director, it’s just an encapsulation of the building process. Although it’s not a necessary part of Builder, I would recommend using it since it’s good design.

I think Build shares the same advantages as Factory: To make client code focus on product interfaces. And it’s easy to extend: The client can extend a new concrete builder from the builder interface and replace the class name in her code without changing the logics.

However, I don’t like the examples on the website. So I’d like to take another example.Suppose CarBuilder is the interface, which is extended by BMWCarBuilder and AudiCarBuilder. Then, the usage will be as follows.

1
2
3
4
CarBuilder cb = new BMWCarBuilder(); // CarBuilder cb = new AudiCarBuilder(); 
Director d = new Director(cb);
d.buildSUV();
Car c = cb.getResult();

If the client wants to build Audi, she just changes the first line and replaces the concrete builder with AudiCarBuilder.

Prototype

Readings:

Prototype is much easier and we can simply find an analogy in Java: Cloneable interface, which requires an implementation of the function clone().

Prototype is aiming to let us create a copy of an object without knowing what its class is. To use copy constructor we can do the same thing, but we would rely on the class, meaning we are creating a new object using CLASS, while we are creating objects from an object with the help of Cloneable. That’s their main difference.

But usually we will call the copy constructor within clone(), so we still need to pay attention to the issue of shallow copy and deep copy. And in the cases of inheritance, clone() of a subclass sometimes may need to call its counterpart(aka. clone()) in its superclass for initializing new objects.

By the way, Prototype Registry builds on Prototype pattern, which normally uses a hash map to cache some frequently used objects. The implementation is usually similar to the follows.

1
2
3
Button b = new Button(10, 40, “red”);
registry.addItem(“landingButton”, button);
Button nb = registry.getByColor(“red”);

Singleton

Readings:

Singleton aims to limit the amount of instances(usually 1) of a certain class.

The implementation is to make the constructor private and to add a static function to serve as a constructor for creating objects.

There are mainly two ways of Singleton:

  1. Lazy loading, which creates the instance(s) when function getInstance() is called for the first time;
  2. Eager loading, which creates the instance(s) at the initialization of the class.

There are two main use cases I can come up with:

  1. To provide a substitute for global variables;
  2. To delay the initialization(with lazy loading) in order to save the memory.

Although the definition of Singleton is simple, the implementation is quite annoying, because the issue of thread safety and potential attacks.

Double-checked locking is an efficient way to solve this issue. However, in some languages(e.x. Java 1.4), a lot of implementations you find are probably problematic. The correct way is to add a seemingly useless local variable(https://refactoring.guru/design-patterns/singleton/java/example#example-2). However, this issue is solved in Java 1.5. So, to simply use volatile can guarantee the thread safety.

In Java, another issue is serialization attack(https://blog.csdn.net/u013256816/article/details/50474678) and reflection attack(https://blog.csdn.net/u013256816/article/details/50525335), which can break the limitation of the amount of instances.

So, the safe implementations of Singleton in Java are as follows.

  1. Eager loading: Enum is highly recommended(https://blog.csdn.net/qq_27093465/article/details/52180865).
  2. Lazy loading: Static nested class is recommended(http://wuchong.me/blog/2014/08/28/how-to-correctly-write-singleton-pattern/), which can defend reflection attack because inner class will not be automatically loaded. However, it’s still susceptible to serialization attack(https://blog.csdn.net/siying8419/article/details/82152921).