Online Book Reader

Home Category

Professional C__ - Marc Gregoire [490]

By Root 1154 0
the desired abstraction and the actual underlying code. Chapter 12 discusses how the STL uses the adapter pattern to implement containers like stack and queue in terms of other containers, such as deque and list.

Example: Adapting a Logger Class

For this adapter pattern example, let’s assume a very basic Logger class. Methods are shown with their implementations directly in the header file. This is not Best Practice, but is done to save space.

#include

#include

class Logger

{

public:

static const std::string kLogLevelDebug;

static const std::string kLogLevelInfo;

static const std::string kLogLevelError;

Logger() { std::cout << "Logger constructor" << std::endl; }

void log(const std::string& level, const std::string& str) {

std::cout << level << ": " << str << std::endl;

}

};

const std::string Logger::kLogLevelDebug = "DEBUG";

const std::string Logger::kLogLevelInfo = "INFO";

const std::string Logger::kLogLevelError = "ERROR";

Code snippet from LoggerAdapter\LoggerAdapter.h

The Logger class has a constructor, which outputs a line of text to the standard console, and a method called log() that writes the given line of text to the console prefixed with a log level.

One reason why you might want to write a wrapper class around this basic Logger class is to change the interface of it. Maybe you are not interested in the log level and you would like to call the log() method with only one parameter, the message itself.

Implementation of an Adapter

The first step in implementing the adapter pattern is to define the new interface for the underlying functionality. This new interface is called NewLoggerInterface and looks as follows:

class NewLoggerInterface

{

public:

virtual void log(const std::string& str) = 0;

};

Code snippet from LoggerAdapter\LoggerAdapter.h

This class is an abstract class, which declares the desired interface that you want for your new logger. It only defines one abstract method which needs to be implemented by any class inheriting from this interface. You can think of NewLoggerInterface as a mix-in class. Mix-in classes are discussed in Chapter 28.

The next step is to write the actual new logger class, NewLoggerAdapter, which inherits from the NewLoggerInterface so that it has the interface that you designed. It also privately inherits from the original Logger class. It is inherited privately so that no functionality from the original Logger class will be publicly available in the NewLoggerAdapter class. The constructor of the new class writes a line to standard output to keep track of which constructors are being called. The code then implements the abstract log() method from the NewLoggerInterface interface by forwarding the call to the original log() method and specifying kLogLevelInfo as log level:

class NewLoggerAdapter : public NewLoggerInterface, private Logger

{

public:

NewLoggerAdapter() {

std::cout << "NewLoggerAdapter constructor" << std::endl;

}

virtual void log(const std::string& str) {

Logger::log(Logger::kLogLevelInfo, str);

}

};

Code snippet from LoggerAdapter\LoggerAdapter.h

Using an Adapter

Since adapters exist to provide a more appropriate interface for the underlying functionality, their use should be straightforward and specific to the particular case. Given the previous example, the following program uses the new simplified interface for the Logger class:

#include "LoggerAdapter.h"

int main()

{

NewLoggerAdapter logger;

logger.log("Testing the logger.");

return 0;

}

Code snippet from LoggerAdapter\TestLoggerAdapter.cpp

When you compile and run this example, it will produce the following output:

Logger constructor

NewLoggerAdapter constructor

INFO: Testing the logger.

THE DECORATOR PATTERN


The decorator pattern is exactly what it sounds like — a “decoration” on an object. The pattern is used to change the behavior of an object at run time. Decorators are a lot like subclasses, but their effects can be temporary. For example, if you have a stream of data that you are parsing and you reach data that represents

Return Main Page Previous Page Next Page

®Online Book Reader