Design patterns: Bridge – With Kotlin examples

It’s time for the Bridge pattern.

The Bridge pattern (also known as Handel/Body) is one of the structural patterns which its intent is:

Decouple an abstraction from its implementation so that the two can vary independently.

That’s the textbook definition, but let’s introduce a problem and show how the Bridge pattern can solve it to understand that definition.

Let’s say that we have a House class with a couple of subclasses WoodHouse and RockHouse. So far so good, but now we want to give them colors and create a yellow house and a red house. For our current subclasses, we will need to create four subclasses combinations which are YellowWoodHouse, YellowRockHouse, RedWoodHouse, and RedRock house.

Adding a new house type that requires creating another two subclasses of the combination and adding another color means creating three subclasses for each house type. The hierarchy will grow exponentially and it will only get worse and worse.

So the problem that we inherit from House class in two directions, the type and color, and these properties are independent of each other. The Bridge pattern can help here by extracting those two properties into two different class hierarchy. This means that the House abstraction will be in a separate class hierarchy, and the color will be in another separate class hierarchy and use composition to connect those separate hierarchy.

Now we can add or change any type of houses without affecting the color class hierarchy and also add more color without affecting the house abstraction and its class hierarchy. So what we did here that we separated or decoupled the abstraction which is the House from its implementation which is the Color so that the two can vary independently and without affecting each other, and that’s the Bridge pattern.

Now let’s take a look at the Bridge pattern structure:

Image by GoF book.

The participants of the Bridge pattern the diagram above showed are:

  • Abstraction (House)
    • Defines the interface of the abstraction and also has a reference to the Implementor.
  • RefinedAbstraction (WooedHouse, RockHouse)
    • Extends the Abstraction.
  • Implementor (Color)
    • Defines the interface for implementation classes.
  • ConcreteImplementor (Yellow, Red)
    • Implement the Implementor.

The client requests went to the abstraction and the abstraction then forwards them to its implementor object.

Now let’s take a look at how the Bridge pattern is implemented in code using Kotlin.

Here we have the interface of the Color and two concrete classes are implement the Color interface.

interface Color {
    fun getColor()
}

class Yellow: Color {
    override fun getColor() {
        println("Yellow")
    }
}

class Red: Color {
    override fun getColor() {
        println("Red")
    }
}

 

Here we have the House interface and you can notice the House has a reference to the implementor Color as stated earlier.

interface House {
    val color: Color
    fun show()
}

class WoodHouse(override val color: Color): House {
    override fun show() {
        print("The wood house color is ")
        color.getColor()
    }
}

class RockHouse(override val color: Color): House {
    override fun show() {
        print("The rock house color is ")
        color.getColor()
    }
}

 

And here is the complete code:

interface Color {
    fun getColor()
}

class Yellow: Color {
    override fun getColor() {
        println("Yellow")
    }
}

class Red: Color {
    override fun getColor() {
        println("Red")
    }
}

interface House {
    val color: Color
    fun show()
}

class WoodHouse(override val color: Color): House {
    override fun show() {
        print("The wood house color is ")
        color.getColor()
    }
}

class RockHouse(override val color: Color): House {
    override fun show() {
        print("The rock house color is ")
        color.getColor()
    }
}

fun main() {
    val yellowWoodHouse = WoodHouse(color = Yellow())
    yellowWoodHouse.show()
    val yellowRockHouse = RockHouse(color = Yellow())
    yellowRockHouse.show()
    val redWoodHouse = WoodHouse(color = Red())
    redWoodHouse.show()
    val redRockHouse = RockHouse(color = Red())
    redRockHouse.show()
}

 

The output will be:

The wood house color is Yellow
The rock house color is Yellow
The wood house color is Red
The rock house color is Red

 

So as recap the Bridge pattern decoupled the abstraction which is the House from its implementation which is the Color so that the two can vary independently.

And that’s it, that’s the Bridge pattern. And as always you can refer to the GoF book for more.

So that’s all I have for this post and I always appreciate feedback and If you have any question please put your questions in the comments.

Till the next pattern.

Leave a Reply

Your email address will not be published. Required fields are marked *