UP | HOME

Intro

This file contains my personal annotations on the Design Patterns subjects that I will be reading on the “Head First: Design Patterns” book.

Source code of the book can be found on: http://wickedlysmart.com/head-first-design-patterns.

Source code of my study: https://github.com/aang7/DesignPatternsExamples/.

Chapter 1

Design principles on STRATEGY pattern:

  1. Identify the aspects of your application that vary and separate them from what stays the same.
  2. Program to an interface, not an implementation.
  3. Favor composition over inheritance.

Formal definition of Strategy pattern

The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Chapter 2

The Observer Pattern

The Observer Pattern defines a one-to-many relationship between a set of objects. When the state of one object changes, all of its dependents are notified.

20221003_151046_6x2ivp.png

The Power of Loose Coupling

When two objects are loosely coupled, they can interact, but they typically have very little knowledge of each other. Loosely coupled designs often give us a lot of flexibility.

Design Principles

Design principles found in this chapter:

  1. Strive for loosely coupled designs between objects that interact.

Chapter 3

The Decorator Pattern

Decorators are meant to add behavior to the object they wrap.

Design Principles

Design principles found in this chapter: 1.Classes should be open for extension, but closed for modification. (This is called the Open-Closed Principle)

Example

the Java.io package is one example of many where the Decorator Pattern is largely used.

20221004_144956_Hxvl16.png

Java I/O also points out one of the downsides of the Decorator Pattern: designs using this pattern often result in a large number of small classes that can be overwhelming to a developer trying to use the Decorator-based API. But now that you know how Decorator works, you can keep things in perspective and when you’re using someone else’s Decorator-heavy API, you can work through how their classes are organized so that you can easily use wrapping to get the behavior you’re after.

Points

Good points:

  • add flexibility to designs, it can add new behaviours on runtime.
  • you can usually insert decorators transparently and the client never has to know it’s dealing with a decorator.
  • stays true to the Open-Closed Principle

Bad points:

  • increase the complexity of the code needed to instantiate the component. Once you’ve got decorators, you’ve got to not only instantiate the component, but also wrap it with who knows how many decorators.
  • add a lot of small classes to a design, and this occasionally results in a design that’s less than straightforward for others to understand.
  • have to be careful when inserting decorators

Chapter 4

The Factory Pattern

Inside the Factory Pattern we have a few variants:

  • Simple Factory: Is a simple way to decouple your clients from concrete classes.
  • Factory Method: Relies on inheritance. object creation is delegated to subclasses, which implement the factory method to create objects.
  • Abstract Factory: Provides an interface for creating families of related or dependent objects without specifying their concrete classes.

Examples of the pattern can be found on my repository1 under this path.

Abstract Factory and Factory method - Comparison

We can say that in this pattern we have the creator and the product. Where the creator is the factory itself and the product is the one that requires the creator. So the we have the creator classes and the product classes.

20221006_151133_tzEe5m.png
Figure 3: factory method general overview of the pattern
20221006_143714_JGd9Ky.png
Figure 4: abstract factory general overview of the pattern
20221006_150512_wFk60t.png
Figure 5: abstract factory general overview of the pattern - Practical Illustration
20221005_164049_z1pNFs.png
Figure 6: example of design - simple factory on the left and abstract on the right
20221005_164219_ymwp0U.png

Principles

  • Depend upon abstractions. Do not depend upon concrete classes. (This is called “Dependency Inversion Principle”) At first, this principle sounds a lot like “Program to an interface, not an implementation,” right? It is similar; however, the Dependency Inversion Principle makes an even stronger statement about abstraction. It suggests that our high-level components should not depend on our low-level components; rather, they should both depend on abstractions.

Points

  • All factories encapsulate object creation.
  • Simple Factory, while not a bona fide design pattern, is a simple way to decouple your clients from concrete classes.
  • Factory Method relies on inheritance: object creation is delegated to subclasses, which implement the factory method to create objects.
  • Abstract Factory relies on object composition: object creation is implemented in methods exposed in the factory interface.
  • All factory patterns promote loose coupling by reducing the dependency of your application on concrete classes.
  • The intent of Factory Method is to allow a class to defer instantiation to its subclasses.
  • The intent of Abstract Factory is to create families of related objects without having to depend on their concrete classes.
  • The Dependency Inversion Principle guides us to avoid dependencies on concrete types and to strive for abstractions.

Chapter 5

The Singleton Pattern

This is easily the shortest pattern so far in the book. The singleton pattern basically handle the creation of only one instance of a determined class.

In java, depending on the version will be the implementation to use. There are basically two ways of implement this pattern

  1. Creating a private constructor with a private field on the class and an static method called getInstance which basically handles the creation and return of the only once instantiated object.
  2. Using an Enum type class.

For more details please refer to this article.

Points

  • The Singleton Pattern ensures you have at most one instance of a class in your application.
  • The Singleton Pattern also provides a global access point to that instance.
  • Java’s implementation of the Singleton Pattern makes use of a private constructor, a static method combined with a static variable.
  • Examine your performance and resource constraints and carefully choose an appropriate Singleton implementation for multithreaded applications (and we should consider all applications multithreaded!).
  • Beware of the double-checked locking implementation; it isn’t thread safe in versions before Java 5.
  • Be careful if you are using multiple class loaders; this could defeat the Singleton implementation and result in multiple instances.
  • You can use Java’s enums to simplify your Singleton implementation.

Footnotes: