📜 ⬆️ ⬇️

Design Pattern "Adapter" / "Adapter"

Read the description of other patterns.

Perhaps we will begin.
To begin with, I will explain a few organizational issues.


Intro


As you have already noticed, this section is not mandatory in my posts about patterns. But I could not begin to write about a particular pattern, without explaining why they are actually needed.

Not so long ago, when I was in junior courses, to my statement “Yes, we already know how to write programs!”, My colleague said, “The maximum that you can write is algorithms, but not programs.” I remember his words until so far with a smile on his face. He was absolutely right, everything we were taught for 3 years (I was in the third year at that time) - the implementation of the basic algorithms from Cormen / Knuth. We really could write these algorithms, could write functions, procedures implementing them. They could even write a class in C ++ or Java in which to describe all the logic of working with this class of objects. But when such classes became two or even three :) problems started. And at any attempt to write any kind of “program”, the invention of the bicycle began (I think that everyone who reads this post, he invented several such bicycles). Then, I began to suspect that there must be something, what theoretical basis, apparatus, mechanism, call it what you want, which in principle will tell me - "how to write programs."
')
It turned out that such a base exists - these are design patterns. By and large, a pattern is a typical solution to common design problems . Patterns solve a number of basic problems associated with programming / designing. This is the invention of the bicycle, the problem of code reuse, the problem of maintaining the code.

Of course, design patterns, if not solved, then simplify the solution of these problems. So, the developer or designer, knowing at least the basic set of patterns, uses them to replace the designed bikes. Code reuse becomes more transparent and justified. And accompanying code written using patterns is at least understandable and not difficult.

Now, it seems to me it is possible to proceed to the consideration of a specific pattern - “Adapter” (“Adapter”).

Problem


Ensure the interaction of objects with different interfaces. Adapt, rather than rewrite, existing code to the required interface.

Description


The Adapter pattern, in fact, is one of the few that programmers put into practice without realizing it. The adapter can be found, perhaps, in any modern program system - be it a simple application or, for example, a Java API.

Let's look in more detail at the problem, for understanding how the Adapter should look. The problem, again, is to reuse the code. In other words, there is a client who knows how to work with a certain interface, let's call it client. There is a class that, in principle, does what the client needs but does not implement the client interface. Of course, programming a new class is quite a waste of time and resources. It is easier to adapt an existing code to a form suitable for use by the client. For this, there is an adapter. Moreover, they separate two types of adapters - the Object Adapter (adapter at the object level) and the Class Adapter (adapter at the class level). We consider both, but in order.

Practical task



For example, consider a simple situation. There is a certain class - SequenceGenerator, which generates sequences of integers, according to a certain law - this is our client. There is an interface — the Generator, which the client uses directly to generate each individual sequence element — this is our client interface. Besides, there is a class RandomGenerator, which is already able to generate random numbers. Of course, the SequenceGenerator cannot use the RandomGenerator to generate elements, because it does not match the client interface. Our task is to write an adapter (in two ways) a RandomGenerator to a SequenceGenerator.

Class diagrams



Object adapter




Class Adapter




So with class diagrams, let's talk about the differences between the adapter at the object level and the adapter at the class level. In fact, the differences are already visible from the title. In the first case, an adaptable object (RandomGenerator) is a field (reference) in the adapter class (RandomGeneratorAdapter), in the second case it is an adapter due to the use of the inheritance mechanism. In real projects, it is recommended to use the Object Adapter, due to its less connectivity with the object to be adapted.

Implementation



Consider the implementation of the task. I implemented the Object Adapter in C ++, the Class Adapter in Java.

Object adapter


class Generator {
public :
virtual int next() = 0;

};

class SequenceGenerator {
private :
Generator *generator;
protected :
public :
SequenceGenerator(Generator& generator);

int * generate( int length);
};

SequenceGenerator::SequenceGenerator(Generator& generator) {
this ->generator = &generator;
}

int * SequenceGenerator::generate( int length) {
int *ret = new int [length];

for ( int i=0; i<length; i++) {
ret[i] = this ->generator->next();
}

return ret;
}

class RandomGenerator {
public :
inline int getRandomNumber() { return 4; }; // It`s really random number.

};

class RandomGeneratorAdapter : public Generator {
private :
RandomGenerator *adaptee;
public :

RandomGeneratorAdapter(RandomGenerator& adaptee);

virtual int next();

};

RandomGeneratorAdapter::RandomGeneratorAdapter(RandomGenerator& adaptee) {
this ->adaptee = &adaptee;
}

int RandomGeneratorAdapter::next() {
return this ->adaptee->getRandomNumber();
}


//

int main( int argc, char *argv[]) {

RandomGenerator rgenerator;
RandomGeneratorAdapter adapter(rgenerator);
SequenceGenerator sgenerator(adapter);

const int SIZE = 10;

int *seq = sgenerator.generate(SIZE);

for ( int i=0; i<SIZE; i++) {
cout << seq[i] << " " ;
}

}


* This source code was highlighted with Source Code Highlighter .


Class Adapter

The classic implementation of the Class Adapter pattern implies the use of multiple inheritance. In Java, you can use interface implementation. In my opinion, it is even more correct.

public interface Generator {

public int next();

}

public class SequenceGenerator {

private Generator generator;

public SequenceGenerator(Generator generator) {
super();
this .generator = generator;
}

public int [] generate( int length) {
int ret[] = new int [length];

for ( int i=0; i<length; i++) {
ret[i] = generator.next();
}

return ret;
}
}

public class RandomGenerator {

public int getRandomNumber() {
return 4;
}
}

public class RandomGeneratorAdapter extends RandomGenerator implements Generator {

@Override
public int next() {
return getRandomNumber();
}

}

//
public class Main {

public static void main( String [] args) {

RandomGeneratorAdapter adapter = new RandomGeneratorAdapter();
SequenceGenerator generator = new SequenceGenerator(adapter);

for ( int i: generator.generate(10)) {
System. out .print(i + " " );
}
}
}


* This source code was highlighted with Source Code Highlighter .


That's all. Waiting for your feedback in the comments.

Source: https://habr.com/ru/post/85095/


All Articles