Object-oriented design is a way of looking at a system or a program as a collection of objects and how they are related to each other. It resembles how we look at real-world objects and the relationship. In contrast to this, the procedural way of looking at a system involves logic and algorithms for implementing a solution to the problem.

Design Process

There is a huge paradigm shift in object-oriented thinking. I have seen that developers who have been doing a lot of procedural programming find it difficult to think in an Object Oriented way and struggle to come up with a good design. Let’s break down this into simple and easy to-do process.

The first step in this process involves a designer to identify the objects in the system. To start with, let’s assume that every element in the problem is an object. Come up with a comprehensive list of all objects in the problem.

The second step is to establish right relationship between each of them. It’s important to make sure that the relationship is comprehensive and covers all aspects of the system.

The relationship between objects can be defined using:

  • is-a relation (Interitance)
  • part-of relation (Composition/Aggregation)
  • has-a/uses relation (Association)

To explain this concept in a simple language, let’s use a real-world example:

  • Mango is a fruit
  • Mango seed is part of Mango
  • Mango tree has Mangoes
  • Mango tree uses (needs) water to grow

This example can be extended to our software design to discern the relationship between objects.

These two together is known as data modelling. In this exercise, it is extremely crucial to identify and keep it close to the real world. When we keep our design closer to the real world, there are a couple of key advantages. First, it makes our brain to easily identify, map and visualize the design. Secondly, it’s easier to establish the relation between the objects and extend a similar relationship to object-oriented programming. Thirdly, it’s easier to apply other object-oriented concepts like inheritance, data encapsulation and so on.

During this process, we can use certain Design Patterns which are kind of blueprint solutions for a few typical software problems that can be customized to our design. For that to happen naturally, we need to be aware and have hands-on experience in major Design Patterns out there. Don’t try to force-fit a design pattern into our problem but rather if a pattern is a natural fit to the problem we are addressing then it makes sense to incorporate it. Data modelling is the macro level designing of the system. If our data modelling goes wrong, everything that follows will have a ripple effect and design will fail.

Next stage is to define a schema or a structure based on the objects identified. This schema is known as Class in an object-oriented language. The class two key components – data members and member functions. Data members are the key data which defines a class. Member functions are the class functions which acts on these data for certain operations. These can be getter/setter functions (getting and setting the data members) or utility functions (any generic function). This step is known as Class design.

Again, we can use a similar method we’ve employed in data modelling to identifying a class structure. Try to visualize a class as a real-world component.

Ask these questions:

  • The composition of the objects
  • What are the functions of each of the components
  • What are the exposed interfaces to the external world
  • How is an external user interacting with those objects .

Class design is a micro level in an object-oriented design of the system.

Both macro & micro level object-oriented design of the system put together makes it whole. We should keep in mind the Open/Closed principle in Object-oriented design when we finalize the design. It says software entities should be open for extension but should be closed for modification.

Final design then can be represented using a UML class diagram. This baseline design should be the reference for all extension and implementation of application features.

A Case Study

Problem Statement

An application needs to be designed for reading from and write to a hardware device register. Different hardware uses a different communication protocol. There are 3 kinds of physical connection possible to the device – USB, Serial and Ethernet. A device can support only one protocol but could support multiple physical interfaces.

Design Process

Identify objects in the problem

  • Device – There are different hardware devices to be supported
  • Protocol – There are different communication protocols to be supported
  • Interface – There are 3 kinds of physical connection to be supported

Establish relationship between objects

  • The Device can be a base class which can be derived further to define concrete and specific devices – Device1, Device2 and so on. Device1 and Device2 is a Device class.
  • The Protocol can be a base class which can be derived further to define concrete protocol classes. Protocol1 & Protocol2 is a Protocol Class.
  • Individual communication Interfaces USB, Serial & Ethernet can be derived classes from an abstract class Interface.
  • A Device has an Interface class, which is owned and initialized at the object creation of Device. Since Device knows the supported Interfaces, it can create specific communication interfaces in the Derived Device class.
  • A Device has a Protocol class, which is owned and initialized at the object creation of Device. Since only one Protocol is supported by a specific Device, this can be initialized by the Derived Device class.
  • Protocol class uses an Interface class which is initialized based on Device input. This is used by the Protocol to initialize and establish a connection to the physical layer.
  • We can use the factory method design pattern to create a Device Class based on the application input.

Class Design

  • Device class can define attributes and functions specific with each of the device. From a user interaction point of view, we need to define, getter/setter functions for communication parameters, read/write functions etc.
  • Protocol class can define attributes and functions specific to each protocol like protocol related settings, read/write functions.
  • Interface function needs to be specific to each of the specific interfaces. It knows how to establish a connection to the actual physical layer. All of the wrapper communication APIs are written in this class