Adapter ( English Adapter ) is a structural design pattern intended for organizing the use of functions of an object that is not available for modification through a specially designed interface . In other words, it is a structural design pattern that allows objects with incompatible interfaces to work together.
| Adapter | |
|---|---|
| Adapter | |
Adapter Template Structure Representation | |
| Type of | structural |
| Purpose | to organize the use of functions of an object that is unavailable for modification through a specially created interface (leads an interface of a class (or several classes) to an interface of the required type) |
| Used in cases | The system supports the required data and behavior, but has an inappropriate interface. Most often, the Adapter pattern is used if it is necessary to create a class derived from a newly defined or already existing abstract class. |
| pros |
|
| Related Templates | Facade Decorator |
| Described in Design Patterns | Yes |
Content
Key Features
Task
The system supports the required data and behavior, but has an inappropriate interface.
Solution Method
The adapter provides for the creation of a wrapper class [1] with the required interface.
Members
The Adapter class brings the interface of the Adaptee class to the interface of the Target class (which is implemented by the Adapter class). This allows the Client object to use the Adaptee (via the Adapter adapter) as if it were an instance of the Target class.
Thus, Client accesses the Target interface implemented by the Adapter class, which redirects the call to Adaptee .
Consequences
The Adapter pattern allows you to include already existing objects in new object structures, regardless of differences in their interfaces.
Comments and Comments
The Adapter pattern allows the design process not to take into account possible differences in the interfaces of existing classes. If there is a class with the required methods and properties (at least conceptually), then, if necessary, you can always use the Adapter template to bring its interface to the desired form.
Close to the Adapter is the Facade pattern, it is not always possible to distinguish one from the other [2] .
Applying a pattern
A typical example of using the Adapter pattern is the creation of classes leading to a single interface of the PHP language function providing access to various DBMS [3] .
A solution to this problem using the Adapter pattern is shown in the figure.
Implementation
Inclusion of an existing class in another class. The interface of the enclosing class is brought in line with the new requirements, and calls to its methods are converted to calls to the methods of the included class.
Implementation Steps
- Make sure you have two classes with incompatible interfaces:
- A useful service is a utility class that you cannot change (it is either third-party or another code depends on it);
- One or several clients - existing application classes that are incompatible with the service due to an inconvenient or mismatched interface.
- Describe the client interface through which application classes could use the service class.
- Create an adapter class by implementing this interface.
- Place in the adapter the field that will store the link to the service object. Usually this field is filled with the object passed to the adapter constructor. In the case of simple adaptation, this object can be passed through the parameters of the adapter methods.
- Implement all client interface methods in the adapter. The adapter must delegate the main work to the service.
- The application should use the adapter only through the client interface. This will make it easy to change and add adapters in the future.
Ruby
module AdapterPattern
# Allows Client to use Adaptees with incompatible interfaces via Adapters with interface Target
# Adaptee
class twitter
def twit
puts 'Twit was published'
end
end
# Adaptee
class Facebook
def post
puts 'Facebook post was published'
end
end
# Target
module WebServiceInterface
def send_message
raise NotImplementedError
end
end
# Adapter
class TwitterAdapter
include WebServiceInterface
def initialize
@webservice = Twitter . new
end
def send_message
@webservice . twit
end
end
# Adapter
class FacebookAdapter
include WebServiceInterface
def initialize
@webservice = Facebook . new
end
def send_message
@webservice . post
end
end
# Client
class Message
attr_accessor : webservice
def send
@webservice . send_message
end
end
def self . run
puts '=> Adapter'
message = Message . new
message . webservice = TwitterAdapter . new
message . send
message . webservice = FacebookAdapter . new
message . send
puts ''
end
end
AdapterPattern . run
Java inheritance
// Target
public interface Chief
{
public Object makeBreakfast ();
public Object makeLunch ();
public Object makeDinner ();
}
// Adaptee
public class Plumber
{
public Object getScrewNut ()
{ ... }
public Object getPipe ()
{ ... }
public Object getGasket ()
{ ... }
}
// Adapter
public class ChiefAdapter extends Plumber implements Chief
{
public Object makeBreakfast ()
{
return getGasket ();
}
public Object makeLunch ()
{
return getPipe ();
}
public Object makeDinner ()
{
return getScrewNut ();
}
}
// Client
public class Client
{
public static void eat ( Object dish )
{ ... }
public static void main ( String [] args )
{
Chief ch = new ChiefAdapter ();
Object dish = ch . makeBreakfast ();
eat ( dish );
dish = ch . makeLunch ();
eat ( dish );
dish = ch . makeDinner ();
eat ( dish );
callAmbulance ();
}
}
Java - composition
// File Chief.java
public interface Chief {
public Object makeBreakfast ();
public Object makeDinner ();
public Object makeSupper ();
}
// File Plumber.java
public class Plumber {
public Object getPipe () {
return new Object ();
}
public Object getKey () {
return new Object ();
}
public Object getScrewDriver () {
return new Object ();
}
}
// File ChiefAdapter.java
public class ChiefAdapter implements Chief {
private Plumber plumber = new Plumber ();
@Override
public Object makeBreakfast () {
return plumber . getKey ();
}
@Override
public Object makeDinner () {
return plumber . getScrewDriver ();
}
@Override
public Object makeSupper () {
return plumber . getPipe ();
}
}
// Client.java file
public class Client {
public static void main ( String [] args ) {
Chief chief = new ChiefAdapter ();
Object key = chief . makeDinner ();
}
}
Scala
package object adapter {
object battlefield {
protected var redTroops : Array [ Troop ] = Array ()
protected var blueTroops : Array [ Troop ] = Array ()
def addTroop ( troop : Troop ) : Unit = {
if ( troop . side == "red" ) {
redTroops : + = troop
} else if ( troop . side == "blue" ) {
blueTroops : + = troop
} else {
throw new Exception ( s "Invalid side $ { troop . side } for troop $ { troop . name } " )
}
}
def getClosestEnemyTroop ( side : String ) : Troop = {
if ( side == "red" ) {
getTroop ( blueTroops )
} else {
getTroop ( redTroops )
}
}
private def getTroop ( troops : Array [ Troop ]) : Troop = {
if ( troops . length == 0 ) {
throw new Exception ( "No available troops" )
}
troops ( 0 )
}
}
class Troop (
val side : String ,
val name : String ,
val closeWeapon : String ,
val distanceWeapon : String
) {
def move ( direction : String , distance : Int ) : Unit = {
println ( s "Troop $ name moves $ direction on $ distance yards" )
}
def attack ( enemyTroop : Troop , attackType : String ) : Unit = {
val weapon = attackType match {
case "distance" => distanceWeapon
case "close" => closeWeapon
case _ => throw new Exception ( s "Invalid attack type $ attackType for troop $ name " )
}
println ( s "Troop $ name attacks enemy troop $ { enemyTroop . name } with their $ { weapon } s" )
}
}
trait LanceKnightTroopTrait {
def moveForward ( distance : Int ) : Unit
def attackClosest ( attackType : String ) : Unit
}
class LanceKnightTroop (
override val side : String ,
override val name : String ,
override val closeWeapon : String ,
override val distanceWeapon : String
)
extends Troop ( side , name , closeWeapon , distanceWeapon )
with LanceKnightTroopTrait {
override def moveForward ( distance : Int ) : Unit = {
move ( "forward" , distance )
}
override def attackClosest ( attackType : String ) : Unit = {
attack ( Battlefield . getClosestEnemyTroop ( side ), attackType )
}
}
object adapter adapter extends abstracttest {
override def run () : Unit = {
val troop = new Troop ( "blue" , "Archers" , "sword" , "longbow" )
val lanceKnightTroop = new LanceKnightTroop ( "red" , "Lance Knights" , "pike" , "crossbow" )
Battlefield . addTroop ( troop )
Battlefield . addTroop ( lanceKnightTroop )
println ( "Output:" )
lanceKnightTroop . moveForward ( 300 )
lanceKnightTroop . attackClosest ( "close" )
}
}
}
// Output:
// Troop Lance Knights moves forward on 300 yards
// Troop Lance Knights attacks enemy troopers Archers with their pikes
PHP5
<? php
class IndependentDeveloper1
{
public function calc ( $ a , $ b ) {
return $ a + $ b ;
}
}
class IndependentDeveloper2
{
public function nameIsVeryLongAndUncomfortable ( $ a , $ b ) {
return $ a + $ b ;
}
}
interface IAdapter
{
public function sum ( $ a , $ b );
}
class ConcreteAdapter1 implements IAdapter
{
protected $ object ;
public function __construct () {
$ this -> object = new IndependentDeveloper1 ();
}
public function sum ( $ a , $ b ) {
return $ this -> object -> calc ( $ a , $ b );
}
}
class ConcreteAdapter2 implements IAdapter
{
protected $ object ;
public function __construct () {
$ this -> object = new IndependentDeveloper2 ();
}
public function sum ( $ a , $ b ) {
return $ this -> object -> nameIsVeryLongAndUncomfortable ( $ a , $ b );
}
}
// in one place we create a specific adapter and then use the interface
$ adapter1 = new ConcreteAdapter1 ();
$ adapter2 = new ConcreteAdapter2 ();
/ **
* Everywhere in the code we do not use classes directly but through the interface
* this function does not matter which class we use, since we rely on the interface
*
* @param IAdapter $ adapter
* /
function sum ( IAdapter $ adapter ) {
echo $ adapter -> sum ( 2 , 2 );
}
sum ( $ adapter1 );
sum ( $ adapter2 );
PHP5.4
<? php
class SomeClass
{
public function someSum ( $ a , $ b )
{
return $ a + $ b ;
}
}
class AnotherClass
{
public function anotherSum ( $ a , $ b )
{
return $ a + $ b ;
}
}
trait TAdaptee
{
public function sum ( int $ a , int $ b )
{
$ method = $ this -> method ;
return $ this -> $ method ( $ a , $ b );
}
}
class SomeAdaptee extends SomeClass
{
use TAdaptee ;
private $ method = 'someSum' ;
}
class AnotherAdaptee extends AnotherClass
{
use TAdaptee ;
private $ method = 'anotherSum' ;
}
$ some = new SomeAdaptee ;
$ another = new AnotherAdaptee ;
$ some -> sum ( 2 , 2 );
$ another -> sum ( 5 , 2 );
PHP5.4 Compact
<? php
trait TAdaptee
{
public function sum ( int $ a , int $ b )
{
$ method = $ this -> method ;
return $ this -> $ method ( $ a , $ b );
}
}
class SomeClass
{
use TAdaptee ;
private $ method = 'someSum' ;
public function someSum ( $ a , $ b )
{
return $ a + $ b ;
}
}
class AnotherClass
{
use TAdaptee ;
private $ method = 'anotherSum' ;
public function anotherSum ( $ a , $ b )
{
return $ a + $ b ;
}
}
$ some = new SomeClass ;
$ another = new AnotherClass ;
$ some -> sum ( 2 , 2 );
$ another -> sum ( 5 , 2 );
Javascript
function Search ( text , word ) {
var text = text ;
var word = word ;
this . searchWordInText = function () {
return text ;
};
this . getWord = function () {
return word ;
};
};
function SearchAdapter ( adaptee ) {
this . searchWordInText = function () {
return 'These words' + adaptee . getWord ();
+ 'found in text' + adaptee . searchWordInText ();
};
};
var search = new Search ( "text" , "words" );
var searchAdapter = new SearchAdapter ( search );
searchAdapter . searchWordInText ();
Python
class GameConsole :
def create_game_picture ( self ):
return 'picture from console'
class Antenna :
def create_wave_picture ( self ):
return 'picture from wave'
class SourceGameConsole ( GameConsole ):
def get_picture ( self ):
return self . create_game_picture ()
class SourceAntenna ( Antenna ):
def get_picture ( self ):
return self . create_wave_picture ()
class TV :
def __init__ ( self , source ):
self . source = source
def show_picture ( self ):
return self . source . get_picture ()
g = SourceGameConsole ()
a = SourceAntenna ()
game_tv = TV ( g )
cabel_tv = TV ( a )
print game_tv . show_picture ()
print cabel_tv . show_picture ()
C #
using System ;
namespace Adapter
{
class MainApp
{
static void Main ()
{
// Create adapter and place a request
Target target = new Adapter ();
target . Request ();
// Wait for user
Console . Read ();
}
}
// "Target"
class Target
{
public virtual void Request ()
{
Console . WriteLine ( "Called Target Request ()" );
}
}
// "Adapter"
class Adapter : Target
{
private Adaptee adaptee = new Adaptee ();
public override void Request ()
{
// Possibly do some other work
// and then call SpecificRequest
adaptee . SpecificRequest ();
}
}
// "Adaptee"
class adaptee
{
public void SpecificRequest ()
{
Console . WriteLine ( "Called SpecificRequest ()" );
}
}
}
Delphi
program Adapter;
{$ APPTYPE CONSOLE}
{$ R * .res}
uses
System.SysUtils;
(* Client use interface of class TTarget realized as TAdapter *)
(* TAdapter redirects *)
type
TTarget = class
function Request: string; virtual;
end;
TAdaptee = class
function SpecificRequest: string;
end;
TAdapter = class (TTarget)
fAdaptee: TAdaptee;
function Request: string; override;
constructor Create;
end;
{TTarget}
function TTarget.Request: string;
begin
Result: = 'Called Target Request ()';
end;
{TAdaptee}
function TAdaptee.SpecificRequest: string;
begin
Result: = 'Called SpecificRequest ()';
end;
{TAdapter}
constructor TAdapter.Create;
begin
fAdaptee: = TAdaptee.Create;
end;
function TAdapter.Request: string;
begin
(* Possibly do some other work and when call SpecificRequest *)
Result: = fAdaptee.SpecificRequest;
end;
var target: TTarget;
begin
try
{TODO -oUser -cConsole Main: Insert code here}
(* create adapter and place a request *)
target: = TAdapter.Create;
WriteLn (target.Request);
WriteLn (# 13 # 10 + 'Press any key to continue ...');
ReadLn;
target.Free;
except
on E: Exception do
Writeln (E.ClassName, ':', E.Message);
end;
end. Notes
- β The closeness of the terms shell and wrapper ( English wrapper - is used as a decorator synonym) sometimes leads to confusion and the Adapter is defined as a synonym for the Decorator pattern, while these are two different patterns and the latter solves a different task, namely, connecting additional obligations to to the object.
- β The difference is that the Facade pattern is designed to simplify the interface, while the Adapter pattern is designed to bring the various existing interfaces to a single, desired look.
- β In older versions of the PHP language, access to the DBMS is implemented as a set of functions, for each DBMS they have different names and, sometimes, a different set of parameters used, which leads to significant problems when switching from one DBMS to another if such a transition is not provided in advance using the Adapter pattern.
Literature
- Alan Shalloway, James R. Trott. Design patterns. New approach to object-oriented analysis and design = Design Patterns Explained: A New Perspective on Object-Oriented Design. - M .: βWilliamsβ , 2002. - p. 288. - ISBN 0-201-71594-5 .
- E. Gamma, R. Helm, R. Johnson, J. Vlissides . Object-oriented design techniques. Design Patterns = Design Patterns: Elements of Reusable Object-Oriented Software. - SPb: βPeterβ , 2007. - p. 366. - ISBN 978-5-469-01136-1 . (also ISBN 5-272-00355-1 )
- Eric Freeman, Elizabeth Freeman. Design Patterns = Head First Design Patterns. - SPb: Peter, 2011. - 656 p. - ISBN 978-5-459-00435-9 .
Links
- Adapter Pattern (Adapter) - purpose, description, implementation in C ++, advantages and disadvantages