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.
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.