How do design patterns solve problems?


Finding appropriate objects

Objects are everything in object-oriented software, obviously.

Objects

Objects are defined as a package that contain both data and procedures.

Anything under a object is usually referred to as a member.

The data of an object is usually referred to as an attribute, but can also be referred to as a property or field.

The procedures/functions of an object is referred to as a method.

Example object in Java

public class myObject{
	// Object's data, also known as a property or attribute or field.
	int x = 5; 
	
	// A procedure for the object, also known as a method.
	static void myMethod(){ 
		System.out.println("I just got executed!")
	}
}
myObject createdObject = new myObject() // creates an instance of the object.
System.out.println(createdObject.x) // prints value of property x of the object, 5
createdObject.myMethod() // runs the myMethod() method defined in the object.
 
// output:
// 5
// I just got executed!

Design Patterns defines the ‘rules’ of object-oriented programming like so:

  1. An object performs a procedure (method call) when it receives a request from a client.
  2. Requests should be the only way to change an object’s data. This ensures all objects are encapsulated, allowing better organization and more defined goals.

As the book says:

“The hard part about object-oriented design is decomposing a system into objects. The task is difficult because many factors come into play: encapsulation, granularity, dependency, flexibility, performance, evolution, reusability, and on and on. They all influence the decomposition, often in conflicting ways.”

The hardest part about creating software isn’t about writing the code - it’s writing the code so that it perfectly collaborates with one another, like a McDonald’s kitchen, and this is no easy task.

This glaring issue has no objective solution; whether you follow an analytical methodology creating each object, function, set of data, or variables corresponding to the problem; or a ‘big picture’ analysis of the relationships and interactions between all your objects - there will never be a single ‘one and for all’ methodology to follow.

This is where design patterns come in, to help you combine and synchronize objects together to make a perfect system.

Determining object granularity

“Objects can vary tremendously in size and number. They can represent everything down to the hardware or all the way up to entire applications. How do we decide what should be an object?”

Your objects will vary in complexity, flexibility and detail.

Keyword!

Granularity is defined by the scale or level of detail in a set of data.

Finding the balance between something broad like creating an object called Person to creating an object like EmployeePaymentValidator is the key to determining object granularity.

  • You don’t want something broad like Person because then too much responsibility will be placed on a single object - making it much harder to encapsulate, organize and read.

  • You don’t want something too specific like EmployeePaymentValidator because too little responsibility will be placed on a single object, rendering it niche and irrelevant.

Danger

The balance you want varies from project to project, but just remember that breaking down objects will do as much harm as much as not breaking down enough.

Design Patterns also addresses this with the Facade to represent an entire subsystem as an object, the Flyweight to support huge number of objects at the finest granularities. Patterns like Abstract Factory and Builder consist of objects only made to creating other objects. Patterns like Visitor, Command consist of objects that only implements a request to another object or group of objects.

Specifying object interfaces

“Every operation declared by an object specifies the operation’s name, the objects it takes as parameters and the operation’s return value. This is known as the operation’s signature. The set of all signatures defined by an object’s operations is called the interface to the object.”

The interface of an object is the ‘body’ of the object. An object’s methods make up that object’s interface.

Keyword!

Interface is defined as a point where 2 systems, subjects, organizations, etc. meet and interact.

In OOP terms, think of it as where objects request things and receive things from one another - where they interact.

Example

interface my_interface = {
	void get_area();
	void get_perimeter();
}
 
public class Square implements my_interface{
	int x = 3;
	int y = 2;
	public void get_area() {
		System.out.println(this.x * this.y);
	}
 
	public void get_perimeter{
		System.out.println(2*this.x + 2*this.y)
	}
}

A class implements the interface, giving it a general structure. The class therefore has this interface where other objects and pieces of code can interact with to attain a certain result.

An method’s signature defines its the number, types and order of the function’s arguments and the return value. This is also known as type annotation.

Example

public static int add(int num, int num2)

The signature of this method contains 3 modifiers:

  • public indicates that it can be called anywhere.
  • static indicates that the method belongs to the class, not instances.
  • int indicates that the method returns an integer value.

Objects can have the same interface, yet have a different implementation of aforementioned interface.

  • When an implementation is decided at run-time, this is called dynamic binding (e.g. method overriding).
  • When it is done when compiling, it is known as static binding (e.g. method overloading).

By allowing objects to share interfaces with different implementations, it makes it really easy to accommodate for all inputs and changes - future-proofing your code.

This is called polymorphism, a key concept in object oriented programming.

Design Patterns help with defining interfaces by identifying the key elements of an interface, what not to put into a interface, the relationships between objects and how polymorphism is implemented in these patterns.

Specifying object implementations

Objects are generally defined by their class.

public class myObject{
	// Object's data, also known as a property or attribute or field.
	int x = 5; 
	// A procedure for the object, also known as a method.
	public void myMethod(){ 
		System.out.println("I just got executed!")
	}
}

Objects are instantiated - as in you create an instance of the object. Once instantiated, you are now able to use the object.

myObject instance_of_myObject = new myObject() 
// new keyword creates a new instance of myObject.
instance_of_myObject.myMethod() // outputs "I just got executed!"

New classes can also be creating in terms of existing classes - as in subclasses. This is called class inheritance, where a subclass “inherits” the members of the parent class.

Note

Inheritance is denoted by an arrow with a triangle in diagrams.

An abstract class refers to a class that’s entirely responsible for creating subclasses. These do nothing by themselves, only providing a common interface when creating a subclass. The operations in abstract classes are called abstract operations. Classes that aren’t abstract are called concrete classes.

Subclasses can override their parent classes’ functions as well as add their own members to it, allowing objects to be broken down to more specific purposes and sets of data.