Bridge

Consider a use case in our travel product where we have two types of reservations:

  • Premium reservations: special benefits such as free cancellation, better cashback, and so on.
  • Normal reservation: normal restrictions.

Also, recall from Chapter 2Packaging Code, that we have two types of sellers:

  • Institutional: those who can give us an API to pull data off and do our bookings.
  • Small scale: those who will use a platform we build as a part of this product to onboard inventory.

The reservations are finally fulfilled by the sellers. The naive implementation will have a matrix of the reservation type for each type of seller. However, very soon, the code will become unmaintainable. As the code grows in complexity, we might find hard-to-engineer binding between interface and implementation.

The is a relationships between the interfaces start getting mixed up with the implementation details. The abstraction and implementation cannot both be independently extended.

The bridge pattern aims to solve this as follows:

  • Decoupling the abstraction from the implementation so that both can vary independently
  • Segregating the interface hierarchy and the implementation hierarchy into two separate trees

This pattern is described here:

The  dummy implementation for the use case mentioned previously is given here:

type Reservation struct {
sellerRef Seller // this is the implementer reference
}

func (r Reservation) Cancel() {
r.sellerRef.CancelReservation(10) // charge $10 as cancellation feed
}

type PremiumReservation struct {
Reservation
}

func (r PremiumReservation) Cancel() {
r.sellerRef.CancelReservation(0) // no charges
}

// This is the interface for all Sellers
type Seller interface {
CancelReservation(charge float64)
}

type InstitutionSeller struct {}

func (s InstitutionSeller) CancelReservation(charge float64) {
fmt.Println("InstitutionSeller CancelReservation charge =", charge)
}

type SmallScaleSeller struct {}

func (s SmallScaleSeller) CancelReservation(charge float64) {
fmt.Println("SmallScaleSeller CancelReservation charge =", charge)
}

Its usage is as follows:

res:= Reservation{InstitutionSeller{}}
res.Cancel() // will print 10 as the cancellation charge

premiumRes:= PremiumReservation{Reservation{SmallScaleSeller{}}}
premiumRes.Cancel() // will print 0 as the cancellation charge
The abstraction here is a struct not an interface, since in Go you can't have abstract structs/interfaces where you can store a reference to the seller implementation.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset