10-adapter-design-pattern

command
v0.0.0-...-3c7c91d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 12, 2024 License: Apache-2.0 Imports: 1 Imported by: 0

README

Description

The Adapter Design Pattern is a struct which adapts an existing interface X to conform to the required interface Y.

Example

Consider the following example:

package main

import "fmt"

// source
type PersonIntf interface {
	FirstName() string
	LastName() string
}

type Person struct {
	firstname, lastname string
}

func (p Person) FirstName() string {
	return p.firstname
}

func (p Person) LastName() string {
	return p.lastname
}

func NewPerson(firstname, lastname string) *Person {
	return &Person{firstname: firstname, lastname: lastname}
}

// target
type EmployeeIntf interface {
	FullName() string
}

type Employee struct {
	fullname string
}

func (e Employee) FullName() string {
	return e.fullname
}

// usage
func PrintEmployeeName(e EmployeeIntf) {
	fmt.Println(e.FullName())
}

func main() {
	p := NewPerson("John", "Smith")
	PrintEmployeeName(p) // error, p does not implement EmployeeIntf
}


In the example above, we simulate the use of a target interface (Employee) where we only have a source interface (Person). And as expected, an error will appear because the Person interface is not compatible with the Employee interface.

Suppose the Employee interface is in an external package that we cannot modify, we may consider modifying the Person interface, as follows:

// source
type PersonIntf interface {
	FirstName() string
	LastName() string
	FullName() string // new
}

type Person struct {
	firstname, lastname string
}

func (p Person) FirstName() string {
	return p.firstname
}

func (p Person) LastName() string {
	return p.lastname
}

func (p Person) FullName() string {
	return fmt.Sprintf("%s %s", p.firstname, p.lastname)
}

The Reason Why This Is Not a Good Practice

By doing above modification, we have violated the Open-Closed Principle. Not to mention that if the Person interface is also in an external package which we cannot modify it.

A Better Approach

First, create an adapter struct that takes Person interface as an internal property.

// adapter
type PersonEmployeeAdapter struct {
	person PersonIntf
}

func NewPersonEmployeeAdapter(p PersonIntf) *PersonEmployeeAdapter {
	return &PersonEmployeeAdapter{person: p}
}

Second, implement all functions according to the target interface (Employee). From the first example above, only FullName() needs to be implemented.

func (a PersonEmployeeAdapter) FullName() string {
	return fmt.Sprintf("%s %s", a.person.FirstName(), a.person.LastName())
}

Finally, we can use the adapter.

func main() {
	p := NewPerson("John", "Smith")
	adapter := NewPersonEmployeeAdapter(p)
	PrintEmployeeName(adapter)
}

Documentation

The Go Gopher

There is no documentation for this package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL