Golang - Adapter Pattern

Golang - Adapter Pattern

The Adapter Pattern, one of the Gang of Four design patterns, is used to enable the interaction between two incompatible interfaces by creating a wrapper object that can translate requests between both interfaces. In Golang, this pattern is quite useful when you have two interfaces, but their functionalities do not match, and you need to make them work together.

Implementation

The Adapter Pattern consists of four components:

  1. Target Interface: the interface that the client is expecting to interact with.

  2. Adapter: the object that implements the Target Interface and wraps the Adaptee.

  3. Adaptee: the interface that needs to be adapted to be used by the client.

  4. Client: the component that uses the Target Interface.

Here is an example implementation of the Adapter Pattern in Golang:

type Target interface {
    Request() string
}

type Adaptee interface {
    SpecificRequest() string
}

type adapteeImpl struct {}

func (a *adapteeImpl) SpecificRequest() string {
    return "Adaptee request"
}

type adapter struct {
    adaptee Adaptee
}

func (a *adapter) Request() string {
    return "Adapter: " + a.adaptee.SpecificRequest()
}

func main() {
    adaptee := &adapteeImpl{}
    target := &adapter{
        adaptee: adaptee,
    }

    fmt.Println(target.Request())
}

In this example, we have two interfaces, Target and Adaptee, that are incompatible. We create a concrete implementation of Adaptee, adapteeImpl, and an adapter that implements the Target interface and wraps the Adaptee interface.

Real World Example

Let's take an example of a payment gateway that accepts payments from different payment providers like PayPal, Stripe, and Amazon Pay. Each payment provider has its own unique interface to connect with the payment gateway. If we want to add a new payment provider, we need to create a new interface and implement it.

To solve this problem, we can create an adapter for each payment provider that implements the payment gateway's standard interface. Let's take an example of PayPal payment provider:

// paypal.go

type PayPal struct {}

func (p *PayPal) MakePayment(amount float32) bool {
    // connect to PayPal and process payment
    return true
}

// amazon.go

type Amazon struct {}

func (a *Amazon) PayAmazon(amount float32) bool {
    // connect to Amazon and process payment
    return true
}

// gateway.go

type PaymentGateway interface {
    ProcessPayment(amount float32) bool
}

type PayPalAdapter struct {
    PayPal *PayPal
}

func (p *PayPalAdapter) ProcessPayment(amount float32) bool {
    return p.PayPal.MakePayment(amount)
}

type AmazonAdapter struct {
    Amazon *Amazon
}

func (a *AmazonAdapter) ProcessPayment(amount float32) bool {
    return a.Amazon.PayAmazon(amount)
}

// main.go

func main() {
    paymentGateway := &PayPalAdapter{
        PayPal: &PayPal{},
    }

    paymentGateway2 := &AmazonAdapter{
        Amazon: &Amazon{},
    }

        // triggers PayPal
    paymentGateway.ProcessPayment(100)

        // triggers Amazon
    paymentGateway2.ProcessPayment(100)
}

In this example, we have a PaymentGateway interface that needs to be implemented by all the payment providers. The PayPal provider has its own unique interface, so we create an adapter, PayPalAdapter, that implements the PaymentGateway interface and wraps the PayPal interface. Now, we can use the PayPal provider with the payment gateway without changing the payment gateway's implementation. We can also imagine to add an adapter for Amazon, which has its own API implemented in Amazon.

Conclusion

In conclusion, the Adapter Pattern is a useful pattern in Golang when you have two incompatible interfaces that need to work together. It creates a wrapper object that can translate requests between both interfaces. The real-world example of a payment gateway shows how we can use this pattern to create adapters for different payment providers without changing the payment gateway's implementation.


References

Did you find this article valuable?

Support Matthias Bruns by becoming a sponsor. Any amount is appreciated!