Adapter design pattern in go
Tags: go, designpatterns, adapter, solid
Published: 2023-03-05 22:27:29


The Adapter design pattern is used when we want to connect two incompatible interfaces or classes so that they can work together. It’s especially useful when we have a legacy system or third-party library that we need to integrate with, but it doesn’t use the same interface as the rest of our code.
In Go, we can implement the Adapter pattern using interfaces, structs, and composition. We can create an interface that defines the methods we need to work with, and then create an adapter struct that implements that interface and wraps the incompatible interface or class.

Here’s an example of the Adapter pattern in an ecommerce system:

Suppose we have an ecommerce system that uses a payment gateway to process payments. The payment gateway provides a payment API that we need to integrate with. However, our system has a different interface for payment processing, and we can’t modify the payment gateway’s API.

To solve this problem, we can create an adapter that implements our payment interface and wraps the payment gateway’s API. Here’s what the code might look like:

```go
type PaymentGateway struct {
    // Payment gateway API implementation
}
func (pg *PaymentGateway) ProcessPayment(amount float64, cardNumber string, cardExpMonth string, cardExpYear string, cardCVV string) error {
    // Process payment using payment gateway API
}
type PaymentAdapter struct {
    paymentGateway *PaymentGateway
}
func NewPaymentAdapter() *PaymentAdapter {
    return &PaymentAdapter{&PaymentGateway{}}
}
func (pa *PaymentAdapter) ProcessPayment(amount float64, card Card) error {
    return pa.paymentGateway.ProcessPayment(amount, card.Number, card.ExpMonth, card.ExpYear, card.CVV)
}
```
In this example, the PaymentGateway struct represents the payment gateway's API implementation, and the PaymentAdapter struct implements our payment interface and wraps the PaymentGateway struct. The NewPaymentAdapter function creates a new PaymentAdapter and initializes the PaymentGateway instance variable. The ProcessPayment method in the PaymentAdapter calls the ProcessPayment method in the PaymentGateway, passing in the required parameters.

Here’s another example of the Adapter pattern in a trade ecosystem:

Suppose we have a trade ecosystem that communicates with various trading partners using different protocols. Some partners use a REST API, while others use a SOAP API. To simplify our code and make it more modular, we can create adapters for each partner’s API that implement a common interface.

```go
type TradeAPI interface {
    GetQuote(symbol string) (float64, error)
    PlaceOrder(order Order) (string, error)
}
type RestTradeAPI struct {
    // REST API implementation
}
func (rta *RestTradeAPI) GetQuote(symbol string) (float64, error) {
    // Call REST API to get quote
}
func (rta *RestTradeAPI) PlaceOrder(order Order) (string, error) {
    // Call REST API to place order
}
type SoapTradeAPI struct {
    // SOAP API implementation
}
func (sta *SoapTradeAPI) GetQuote(symbol string) (float64, error) {
    // Call SOAP API to get quote
}
func (sta *SoapTradeAPI) PlaceOrder(order Order) (string, error) {
    // Call SOAP API to place order
}
type TradeAPIAdapter struct {
    tradeAPI TradeAPI
}
func NewTradeAPIAdapter(tradeAPI TradeAPI) *TradeAPIAdapter {
    return &TradeAPIAdapter{tradeAPI}
}
func (taa *TradeAPIAdapter) GetQuote(symbol string) (float64, error) {
    return taa.tradeAPI.GetQuote(symbol)
}
func (taa *TradeAPIAdapter) PlaceOrder(order Order) (string, error) {
    return taa.tradeAPI.PlaceOrder(order)
}


```
In this example, we define a `TradeAPI` interface that specifies the methods we need to communicate with trading partners. We then create implementations of this interface for the REST and SOAP APIs. Finally, we create a `TradeAPIAdapter` struct that wraps an implementation of the `TradeAPI` interface and implements the `TradeAPI` interface itself.

Using the `TradeAPIAdapter`, we can abstract away the differences between the different APIs and use a common interface to communicate with all of our trading partners.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/26n5um7lspcuij4wg96c.png)

**In Proxy Design Pattern, We generally followed similar kind of things (Interface, Struct,composition).
**
So Is there any similarity between Proxy Design pattern and Adapter design pattern?

Yes, there is a similarity between the Adapter design pattern and the Proxy design pattern. Both patterns involve creating a new object that acts as an intermediary between the client code and another object, but they do so for different reasons.

The Adapter pattern is used when we need to connect two incompatible interfaces or classes so that they can work together. We create an adapter object that wraps the incompatible object and implements the interface that the client code expects.

The Proxy pattern, on the other hand, is used when we want to control access to an object or provide additional functionality without modifying the object itself. We create a proxy object that looks and behaves like the original object but adds some additional behaviour or constraints, such as caching results or limiting access to certain methods.

Both patterns use composition to create a new object that delegates work to the original object, but they do so for different reasons. The Adapter pattern is focused on creating a new interface that is compatible with the existing code, while the Proxy pattern is focused on adding functionality to an existing interface.

Conclusion: The choice of which pattern to use depends on the specific needs of the system. If we need to connect two incompatible interfaces or classes, then the Adapter pattern is the best choice. If we need to add functionality or control access to an object, then the Proxy pattern is the better option.

By understanding the similarities and differences between these two patterns, we can choose the one that is best suited for our needs and build more robust and flexible systems.