Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using the Composite Pattern to Turn the Lights on

DZone's Guide to

Using the Composite Pattern to Turn the Lights on

Learning design patterns can sometimes be a bit painful. This post attempts to make one such pattern easier to learn, namely the Composite pattern.

· Java Zone ·
Free Resource

How do you break a Monolith into Microservices at Scale? This ebook shows strategies and techniques for building scalable and resilient microservices.

Design patterns are probably one of the most popular topics in the Java blogosphere. Yet many times, the examples used to illustrate the different design patterns are not very engaging. To remedy that, this post explains the Composite pattern in a fun way.

Since there are already many descriptions of this pattern out there, we will not repeat it again. The only thing to remember is that the Composite pattern is used to apply a recursive action on a tree structure. 

Composite Pattern Example

As we said, the whole point of this post is the example, so let’s get on with it!

Imagine a building, perhaps a hotel, with several floors, and each floor containing several rooms.

This hotel is very special though, because it does not have a master switch box. Therefore, whenever it is necessary to turn on/off the lights, someone has to go floor by floor and room by room flipping the corresponding switches.

In order to model the hotel, we will start by defining an interface with the basic operations to switch the lights on and off. The interface will be called ‘Component’ to use the terminology normally associated with the Composite pattern.

public interface Component {
   void switchLightsOn();
   void switchLightsOff();
}

 

Next, we define the classes to represent the hotel: Building, Floor, and Room. Each class implements the interface according to these rules:

  • The Building is considered to have the lights on/off when all its floors are on/off
  • Each Floor is considered to have the lights on/off when all its rooms are on/off
  • Each Room represents, internally, its on/off state

With these rules in mind, here are the definitions of the three classes: 

Building

public class Building extends ArrayList<Floor> implements Component{

   @Override
   public void switchLightsOn() {
      for (Floor floor : this) {
         floor.switchLightsOn();
      }
   }

   @Override
   public void switchLightsOff() {
      for (Floor floor : this) {
         floor.switchLightsOff();
      }
   }
}

 

Floor

public class Floor extends ArrayList<Room> implements Component {

   private int floorNumber;

   public Floor(int floorNumber){
      this.floorNumber=floorNumber;
   }

   @Override
   public void switchLightsOn() {
      for (Room room : this) {
         room.switchLightsOn();
      }
   }

   @Override
   public void switchLightsOff() {
      for (Room room : this) {
         room.switchLightsOff();
      }
   }
}

 

Room

public class Room implements Component {

   private boolean lightsOn = false;
   private int roomNumber;

   public Room(int roomNumber){
      this.roomNumber=roomNumber;
   }

   @Override
   public void switchLightsOn() {
      lightsOn = true;
   }

   @Override
   public void switchLightsOff() {
      lightsOn = false;
   }

   public boolean isLightsOn() {
      return lightsOn;
   }
}

 

Just a few comments about the above definitions:

  • For convenience, the classes Building and Floor extend ArrayList to inherit its containment capability
  • Building forwards the calls to each of its floors and, similarly, Floor forwards the calls to each of its rooms. This “recursive forwarding” is a distinctive feature of the Composite pattern.
  • The overall effect is that any action on Building starts a chain of recursive operations that propagate through Floors and Rooms. This “domino effect” is also characteristic of the Composite pattern. 

To see these ideas in action, let’s run a test. First, we need to create a building (by default, the lights are off). Then, after calling ‘switchLightsOn’ on the building, the lights of all rooms in the hotel switch on.

public class CompositeTest {

   private Building building;

   @Before
   public void createBuilding(){

      building = new Building();

      //1st floor
      Floor floor = new Floor(1);
      floor.add(new Room(11));
      floor.add(new Room(12));
      building.add(floor);

      //2nd floor
      floor = new Floor(2);
      floor.add(new Room(21));
      floor.add(new Room(22));
      floor.add(new Room(23));
      building.add(floor);

      //3rd floor
      floor = new Floor(3);
      floor.add(new Room(31));
      floor.add(new Room(32));
      floor.add(new Room(33));
      building.add(floor);

   }


   @Test
   public void buildingLightsAreOn(){

       //checking that all rooms are off
      for(Floor floor : building){
         for(Room room : floor){
            assertEquals(false,room.isLightsOn());
         }
      }

      building.switchLightsOn();

       //checking that all rooms are on
      for(Floor floor : building){
         for(Room room : floor){
            assertEquals(true,room.isLightsOn());
         }
      }
   }
}

 

I hope you have enjoyed this example. If you want to give it a go yourself, here’s the link to the source code of the Composite pattern example.

How do you break a Monolith into Microservices at Scale? This ebook shows strategies and techniques for building scalable and resilient microservices.

Topics:
java ,design pattern ,composite pattern ,recursion ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}