⛵ + Object Composition =

Launch Academy

By Launch Academy

February 1, 2022

Object-oriented programming can be a tough concept to grasp for a beginning programmer. Its usually the first major obstacle in your learn-to-code journey. Launchers are introduced to objects early in Ignition (our pre-work program), where we break the concept down into easily digestible parts.

What defines an object? How do we know when an object is too complex? Detemining the correct composition of an object and the circumstances that warrant splitting a concept into multiple objects is one of the fundamentals of object-oriented programming. At the core of object composition is the Single Responsibility Principle.

Single Responsibility Principle

How do we decide what belongs in a single class?

This question is answered by the Single Responsiblity Principle. Formally, the Single Responsibility Principle states that "a class should have one, and only one, reason to change".

In practice, this means that each class should only do one thing, and you should be able to explain the purpose of a class in a single sentence. So if you need to use the words "and" or "or" to describe the purpose of a class, that class probably has more than one purpose, and should be split into multiple classes.

Let's say we're trying to represent a canoe and an oil tanker in our application. Should this be one class, or two? If we represented these two objects as instances of a single class,Boat, what would the purpose of this class be? "An object that transports people and oil across small and large bodies of water." Even though we're oversimplifying canoes and oil tankers quite a bit, the purpose that we present above still violates the Single Responsibility Principle. There are two ands, which is two too many.

What if we made these two separate classes? Then we might have:

Canoe: An object that transports people across small bodies of water OilTanker: An object that transports oil across large bodies of water

As two separate classes, Canoe and OilTanker each have a single responsibility.

Sailboats

Continuing with our boat theme, let's consider an object: Sailboats. As you may know, sailboats are incredibly complex objects. Some attributes of a sailboat we might want to characterize are:

  • Mainsail Type
  • Mainsail Size
  • Jib Type
  • Jib Size
  • Boat Length
class Sailboat
  attr_reader :mainsail_type, :mainsail_size, :jib_type, :jib_size, :length

  def initialize(mainsail_type, mainsail_size, jib_type, jib_size, length)
    @mainsail_type = mainsail_type
    @mainsail_size = mainsail_size
    @jib_type = jib_type
    @jib_size = jib_size
    @length = length
  end
end

In this case, however, the Sailboat class is taking responsibility for not just properties of the sailboat (i.e., length), but is also in charge of attributes of the mainsail and jib as well (i.e., type, size). From an organizational standpoint, this may seem a little messy, but still manageable. What if we consider adding another attribute, like color, to the mainsail and jib? Now our Sailboat class would look like so:

class Sailboat
  attr_reader :mainsail_type, :mainsail_size, :mainsail_color, :jib_type, :jib_size, :jib_color, :length

  def initialize(mainsail_type, mainsail_size, mainsail_color, jib_type, jib_size, jib_color, length)
    @mainsail_type = mainsail_type
    @mainsail_size = mainsail_size
    @mainsail_color = mainsail_color
    @jib_type = jib_type
    @jib_size = jib_size
    @jib_color = jib_color
    @length = length
  end
end

The Sailboat class is now burdened with taking in attributes about two sails: the mainsail and the jib, that technically have nothing to do with the Sailboat itself. The Sailboat class simply cares that there is a mainsail and a jib - but should it be concerned with the color and type of these sails?

There must be a better way!