Software Design Patterns: Why, What, and How

Javier Gonzalez
The Startup

--

Why?

There are two things that you need to learn to be successful in creating software. The first one is usually a language, a programming language, and the second one is a design. 👀 No, I am not talking about graphics design. I am talking about engineering design.

Your goal when creating software is to tell the computer what to do. Thus, knowing a progamming language makes an excellent first need. By learning a programming language, you become a coder or a programmer. That is just the first step. Any kid who finishes elementary school can write, but that does not mean that any kid who finishes elementary school can write a book. Most people can kick a ball, but only a few become professional players.

A software engineer aims to be as proficient as that book writer or professional player. As engineers, our work is to deal with complexity, i.e., with things consisting of many different and connected parts. For instance, in writing a book, knowing the language is essential, but it is not enough; the complexity is not writing sentences. The complexity exists elsewhere: the structure of the ideas, what we are going to talk about, how we divide the topic, and more importantly, how we connect these parts. Design Patterns help us to deal with that — the parts and their connections.

What?

A pattern is a template. Solving a problem by customizing a template is more comfortable than starting from scratch. There are templates for how a house should be structured, its parts, and connections. Same for vehicles and electrical circuits. Just follow the template, and you will have a solution. The template warranty good results.

What about innovation and creativity? Well, let put this in this way: on the one hand, you have a template that had been used several times and had successfully created products with some level of quality. On the other hand, you can take the risk of developing something new. Both options are available. What do you prefer? What can you afford?

Most of the time, civil, electrical, and mechanical engineers follow a pattern, i.e., go for the proven solution. Cars has 4 wheels. Homes has doors and windows, etc.

What about the software?

Engineers have been developing software for more than 50 years. For sure, some problems have reappeared again and again with a wide variety of solutions. There is likely one that became “the solution” for a given scenario. Therefore, a pattern emerged. What kind of problems are we discussing? Well, for instance, in object-oriented programming:

a) What if we have a data source (a component) and other(s) components need continuous access to that data?

b) What if we need to ensure that only one object exists from a particular class?

c) What is the best way to select the algorithm to be applied to a specific input in runtime?

d) How to be sure that we created an object with values in all its attributes?

e) and so on.

Patterns are templates to solve problems. Patterns help us to define the parts involved, and the relationships among these parts. Moreover, we name patterns to make them easy to be remembered. For example, we have Observer, Singleton, Strategy, Builder, Factory, Adapter, Memento, and so forth. Let us review an example.

How?

Enough theoretical background. Let me introduce one design pattern to connect the dots between theory and practice: The Observer Pattern.

Figure 1. Observer Pattern: class diagram decorated with some cartoons

Problem: What if we have a data source (a component) and other(s) components need continuous access to that data?

Sharing data among objects is a recurrent problem.

Solution: we need an instance to observe another. Therefore,

Which are the elements?

We have an element that is observing another element. Therefore, we can say that we have an observer and an observable. These are generic roles, and depending on our particular problem, we will have specific objects full-filling these roles. For instance, a Student can be an Observer and observe a Teacher, which will assume the Observable’s role. How can we be sure that these objects will fulfill their roles? We will make them to sign a contract 😏. That means, we will make our particular classes (such as Student and Teacher) to implement an interface or to inherit from another class. An abstract class is a good idea since we do not want to create objects that are just unidentified Observers or Observables. Therefore, we need abstract classes that will define attributes and operations for Observer and Observable roles. And, we need our concrete classes commit to perform these roles –Student will be an Observer and Teacher will be an Observable. Figure 1 shows our elements and their relationships.

Which are their relationships?

Now, how to connect the observer and observable? Well, everything distills into calling methods. Calling a method from the observable to the observer to say “Hello, I am doing something important here” or “Ey, I just update the value of this variable that you care about”. And then, from the observer to the observable to say “Tell me more, I am interested”. You should be thinking that if the observable is going to notify its observers, it needs to know who is observing. That’s right.

How does all this look as source code?

Let’s program the pattern by tracking it from the top-down. I use Java as a programming language.

Step 1. Main.java — Let us create one Student and one Teacher. And, let the teacher know that the Student will be observing. What is happening here? Well, (1) The Teacher object is using his addObserver() method, a method inherited from the abstract class Observable. And, (2) If we have an addObserver() method is because there is a data structure in that class, a data structure to store references to Observer objects. This is like a Teacher object having an array (or list) to keep a reference to all these Student objects interested in observing it. Line 6 in Figure 4 will confirm our guess.

Figure 2. Main.java

Step 2. Teacher.java — Our teachers are going to be observables. Thus extends the Observable class. The good news, Java API provides an implementation of such a class. So, no need to worry about the data structure and the related methods. Our responsibilities are:

  1. Import the package java.util and make your data source to inherit from Observable.
  2. In any place (method) where something significant happens, that needs to be communicated to the observers, call the methods setChanged() and notifyObservers().
Figure 3. Teacher.java –Observable

We are inheriting these methods —setChanged() and notifyObservers(); consequently, we do not need to worry about their definition. We merely call them in these places where a significant event happens, such as when a variable changes value. You can imagine the method notifyObservers() as having a loop that iterates the observer’s container and for each entity in the container, it calls the entity’s update() method. See lines 21 and 22 in Figure 4. Figure 4 shows what the implementation of the Observable class looks like in the Java API.

Figure 4. The implementation of the Observable class looks like this in the Java API

Step 3. Student.java — Finally, our Students. Only one important thing to do, they should have a method update() since we have Observables calling that method. Our Student class should sign a contract to be Observer. We need an interface with that method signature, and we should make our observers to implement that interface. The Java API provide us such interface. So,

  1. Import the package java.util and make these classes that need access to the data source to implement Observer.
  2. Override the update() method to provide a body. That will look like the code in Figure 5.
Figure 5. Student.java — Observer

Notice how notifyObservers() sends to update() a reference to the Observable that is calling the update(). Thus, the observer can use the reference to contact the observable. Specifically, in our example, the observer (Student) can call getter methods in the observable (Teacher) to access the updated information (the attribute importantData).

Challenge

Now that we have a vanilla implementation see if you can create a class DataSource that produces random numbers. Bonus points if you can add a Timer to that class, thus having random numbers created every N seconds. Make that class Observable. Then create a class View, make View a JFrame, and add widgets (at least a JLabel). Can you make the random numbers to be shown on the label?

Is the observer pattern a common solution to connect functionality and views? Yes, it is. It is a core concept for the Model-View-Controller architectural pattern. But that’s another story.

I regularly write about Software & AI — if you would like to read my future posts, then please give me a follow, subscribe, or share a coffee.

--

--

Javier Gonzalez
The Startup

Specialized in human-centered, self-adaptive intelligent systems and passionate about teaching emerging technologies.