Real World Implementation Of Adapter Pattern
Consider the following scenario: your application uses a MySQL database, but you need to switch to a PostgreSQL database. The two databases use different methods for establishing connections, executing queries, and so on.
Here's a class diagram for the database example using the Adapter pattern,
This diagram illustrates the relationship between
the MySQLDatabase
, PostgreSQLDatabase
, and DatabaseAdapter
classes.
The DatabaseAdapter
adapts the PostgreSQLDatabase
to the MySQLDatabase
interface, allowing instances of PostgreSQLDatabase
to be used
where MySQLDatabase
instances were expected.
Real World Implementation
First, let's define the original MySQL class:
class MySQLDatabase {
connectToMySQL(uri: string): void {
console.log(`Connecting to MySQL database at ${uri}`);
// Implementation...
}
executeMySQLQuery(query: string): void {
console.log(`Executing MySQL query: ${query}`);
// Implementation...
}
}
Your application code may be scattered with calls to these methods, like this:
let database = new MySQLDatabase();
database.connectToMySQL("mysql://localhost:3306/mydb");
database.executeMySQLQuery("SELECT * FROM users");
Now, you decide to switch to PostgreSQL, but you can't just replace
the MySQLDatabase
instances with PostgreSQLDatabase
instances, because
the PostgreSQLDatabase
class has a different interface:
class PostgreSQLDatabase {
connectToPostgres(uri: string): void {
console.log(`Connecting to PostgreSQL database at ${uri}`);
// Implementation...
}
executePostgresQuery(query: string): void {
console.log(`Executing PostgreSQL query: ${query}`);
// Implementation...
}
}
Here's where the Adapter pattern comes in. You can create an adapter class that
translates the MySQLDatabase
interface to the PostgreSQLDatabase
interface:
class DatabaseAdapter {
private database = new PostgreSQLDatabase();
connectToMySQL(uri: string): void {
this.database.connectToPostgres(uri);
}
executeMySQLQuery(query: string): void {
this.database.executePostgresQuery(query);
}
}
Now, you can use DatabaseAdapter
in your application where MySQLDatabase
was
expected:
let database = new DatabaseAdapter();
database.connectToMySQL("mysql://localhost:3306/mydb");
database.executeMySQLQuery("SELECT * FROM users");
The DatabaseAdapter
makes your application believe it's still working with
a MySQLDatabase
, but under the hood, it uses a PostgreSQLDatabase
. This
allows you to switch databases with minimal changes to your application's code.
Advantages Of The Adapter Pattern
The Adapter pattern offers several advantages.
Reusability and flexibility
The Adapter pattern allows developers to reuse existing code without significant modifications. This is particularly useful when dealing with legacy code or third-party libraries.
In the above example, the PostgreSQLDatabase
class can be reused without
any changes, even though its interface doesn't match the interface used by
the rest of the application:
class PostgreSQLDatabase {
connectToPostgres(uri: string): void {
console.log(`Connecting to PostgreSQL database at ${uri}`);
// Implementation...
}
executePostgresQuery(query: string): void {
console.log(`Executing PostgreSQL query: ${query}`);
// Implementation...
}
}
Decoupling
The Adapter pattern helps in decoupling the client and the services which reduces the dependencies between them. Changes to one component do not directly impact others. This makes the code more maintainable.
In the given example, if the PostgreSQLDatabase
class changes, the rest of
the application isn't affected, because these changes are encapsulated in
the DatabaseAdapter
class:
class DatabaseAdapter {
private database = new PostgreSQLDatabase();
connectToMySQL(uri: string): void {
this.database.connectToPostgres(uri);
}
executeMySQLQuery(query: string): void {
this.database.executePostgresQuery(query);
}
}
Enabling interoperability
The Adapter pattern can help different parts of a system work together even if their interfaces don't match. This is especially important when you want to integrate existing components or libraries into your application.
In our example, the DatabaseAdapter
class enables the PostgreSQLDatabase
to work with the rest of the application that expects a MySQLDatabase
interface:
let database = new DatabaseAdapter();
database.connectToMySQL("mysql://localhost:3306/mydb");
database.executeMySQLQuery("SELECT * FROM users");
The Adapter pattern is best used when it solves a specific problem like integrating an incompatible interface or when it simplifies the codebase by hiding complex or unnecessary details.
Time To Transition From JavaScript To TypeScript
Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.
SEE COURSE DETAILSWhat Can You Do Next 🙏😊
If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for ssoftware developers.