From the Language of Code to Fairy Tales: Uniting Different Worlds with the Adapter Pattern

[tr] Türkçe Oku

2023-06-15

Once upon a time, there were two friends from two different worlds: the Electric Vacuum Cleaner and the Electric Outlet. The Electric Vacuum Cleaner needed energy and wanted to get this energy from the Electric Outlet. However, there was a problem. The plug of the Electric Vacuum Cleaner did not fit the Electric Outlet. They were both produced in different standards and could not communicate directly with each other.

In this case, a hero emerged: the Adapter. The Adapter created a bridge between the plug of the Electric Vacuum Cleaner and the Electric Outlet. The plug of the Electric Vacuum Cleaner was plugged into one side of the Adapter and the other side of the Adapter was plugged into the Electric Outlet. Thus, the Electric Vacuum Cleaner got the energy and was able to perform its function.

This fairy tale explains the basic logic of the Adapter Pattern. The Adapter Pattern creates a bridge between two classes or interfaces that cannot communicate directly with each other. In this way, it transforms the interface of a class into the interface shape that another class expects.

Adapter Pattern Diagram

As you can see in the diagram, the Target class is used by the Adapter class. The Adapter class transforms the specificRequest method of the Adaptee class into a request method that the Target class can understand.

Below you can find examples of the Adapter Pattern in C#, Java, Go, and Rust languages.

C#

// Target
public interface ITarget
{
    string Request();
}

// Adaptee
public class Adaptee
{
    public string SpecificRequest()
    {
        return "Specific Request";
    }
}

// Adapter
public class Adapter : ITarget
{
    private readonly Adaptee _adaptee;

    public Adapter(Adaptee adaptee)
    {
        _adaptee = adaptee;
    }

    public string Request()
    {
        return _adaptee.SpecificRequest();
    }
}

Java

// Target
public interface Target {
    String request();
}

// Adaptee
public class Adaptee {
    public String specificRequest() {
        return "Specific Request";
    }
}

// Adapter
public class Adapter implements Target {
    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    public String request() {
        return adaptee.specificRequest();
    }
}

Go

// Target
type Target interface {
	Request() string
}

// Adaptee
type Adaptee struct{}

func (a *Adaptee) SpecificRequest() string {
	return "Specific Request"
}

// Adapter
type Adapter struct {
	Adaptee *Adaptee
}

func (a *Adapter) Request() string {
	return a.Adaptee.SpecificRequest()
}

Rust

// Target
pub trait Target {
    fn request(&self) -> &'static str;
}

// Adaptee
pub struct Adaptee;

impl Adaptee {
    pub fn specific_request(&self) -> &'static str {
        "Specific Request"
    }
}

// Adapter
pub struct Adapter {
    adaptee: Adaptee,
}

impl Target for Adapter {
    fn request(&self) -> &'static str {
        self.adaptee.specific_request()
    }
}

In these examples, the Adapter class or struct transforms the specificRequest method of the Adaptee class or struct into the request method of the Target interface or trait. In this way, the codes using

When we examine the examples of the Adapter Pattern in these four languages, we can see that each language exhibits a different approach according to its own characteristics. However, the basic principle is the same: a class or structure (Adaptee) is made usable by another class or structure (Target).

In these examples, the Adapter class or structure transforms the specificRequest method of the Adaptee class or structure into the request method of the Target interface or trait. In this way, the codes using the Target interface or trait can use the features of the Adaptee class or structure through the Adapter.

The Adapter Pattern provides compatibility between two classes or structures and thus enables a class or structure to be transformed into the interface shape expected by another class or structure. This increases the reusability of the code and provides a more flexible design.

These examples demonstrate how the Adapter Pattern can be implemented in different programming languages. Remember that each language has its own characteristics and syntax, so the implementation in each language may be slightly different. However, the basic principles of the Adapter Pattern are the same in every language.



More posts like this

The Dance of Components: The Composite Design Pattern

2023-06-22 | #composite-pattern #design-patterns #structural-patterns

Once upon a time, there was a tree in a forest. This tree was a complex structure with leaves and branches. Each branch could have smaller branches and leaves on it. The tree worked as a whole, holding its branches and leaves together. This tree is an example of the Composite design pattern. The tree (Composite) contains two types of components: branches (also Composite) and leaves (Leaf). Both branches and leaves implement the same interface (Component) recognized by the tree.

Continue reading 


Gaining Flexibility by Building Bridges: Analysis and Implementations in Four Different Languages with the Bridge Design Pattern

2023-06-22 | #bridge-pattern #design-patterns #structural-patterns

Once upon a time, there were two kingdoms. Despite being very close to each other, a wide and deep river was located between them. This river made it difficult for the kingdoms to interact with each other. To solve this situation, both kingdoms decided to build a bridge. This bridge became an interface that facilitated communication between the two kingdoms. However, the bridge had different structures and features on each side.

Continue reading 


Decorator Design Pattern: The Adornments of Software

2023-06-15 | #decorator-pattern #design-patterns #structural-patterns

Once upon a time, there was an object named “Component”. This object was used to perform a specific function. However, sometimes it was necessary to extend or modify this function. That’s where “Decorators” came into play. Decorators are objects that “decorate” or extend the Component. A Decorator comes on top of a Component and extends or modifies its function. This is used to extend the functionality of the Component without changing it itself.

Continue reading 