The Bridge Pattern

The Bridge Pattern decouples an abstraction from its implementation to enable the two to vary independently. It puts abstraction and implementation in separate class hierarchies. Instead of implementing the abstraction, the “implementation” uses it.

Let’s illustrate it. We want our software to draw maps which are constituted of different shapes (points, lines, polygons, etc.). We could create a Renderer interface with implementations for each shape:

The problem with this design is that we multiply implementations for each shape. To avoid multiplying classes (one of the pattern’s advantages), we can use the bridge pattern:

The bridge is Renderer/Shape

The code would look like:

class Shape {
  private Renderer renderer;
  private int radius;

  public Shape(Renderer renderer, int radius) {
    this.renderer = renderer;
    this.radius = radius;
  }

  public void draw() {
    renderer.drawCircle(radius);
  }
}

// code using the bridge
FlashyRenderer renderer = new FlashyRenderer();
Shape point = new Point(renderer); // which sets the renderer in the class
point.draw();

renderer.updateColor(); // the body of this method may request the shape to re-draw

When to use it?

  • When we multiply classes having the same behavior on similar objects.
  • When abstractions and implementations must be extensible independently.
  • When the implementation must be selected or changed at run-time.
  • When the implementation has no impact on client code.

The Visitor Design Pattern

Design patterns are the fun of Object Oriented Programming. It is the artsy side of OOP! In this post, I am illustrating the visitor pattern to understand what it is and what it is meant to be.

When I moved in the US, I asked if doctors visited their patients. I was told it was only for emergency. But in France, it is a common practice. A doctor may have scheduled days to visits patients. His secretary would set up the appointments and let him know where and when.

In the Visitor pattern, the secretary is what the pattern calls “client,” or the dispatcher. She has the list (object structure) of patients (called “elements” which are the data objects) for the day, and calls the patients to make sure they “accept” the doctor (called “visitor” – perform the operation) when he comes for the visit.

The doctor performs a different operation depending on the patient. For example, Fred is a patient who has the flu, and Bob a broken wrist. When the doctor visits Fred, he will prescribe antiobotics, but for Bob, he will ask him to go to the clinic to get a cast.

In pseudo code, the visitor pattern looks like:

for (patient in the list) {
secretary.calls(patient.accept(doctor))
}

class patient {
  function accept(doctor) {
    doctor.performVisit(self)
  }
}

// sub classes
class patientWithFlu {
  function accept(doctor) {
    getMouthMask()
    doctor.performVisit(self)
  }
}
class patientWithBrokenBone {
  function accept(doctor) {
    getTylenol();
    doctor.performVisit(self)
  }
}

class doctor {
  function performVisit(patientWithFlu) {
    checkIfHasFever(patientWithFlu)
    prescribe(patientWithFlu, antiobotics)
  }

  function performVisit(patientWithBrokenBone) {
    checkBone(patientWithBrokenBone)
    prescribe(patientWithBrokenBone, painMedicine)
    putCast(patientWithBrokenBone)
  }
}

Obviously, one of the disavantages is the complexity it brings, but the advantage is the flexbility to change the operations without affecting the data objects. For example, let’s say the regulations change tomorrow and casts are required to be done in clinics. Our traveling doctor cannot do it anymore during his visit. The doctor class is the only one that needs to be changed. The patientWithBrokenBone stay the same.

function performVisit(patientWithBrokenBone) {
  checkBone(patientWithBrokenBone)
  prescribe(patientWithBrokenBone, painMedicine)
  giveContactInfo(patientWithBrokenBone, clinicA)
}

In Summary:
Client
-> calls each element of a list to accept the visitor

Element (each element requires a different type of operation)
-> accepts the visitor and let him do what he is supposed to do

Visitor
-> performs the operation with the element