Policy Based Design Using C++ Typemaps
Although the idea of policies has existed long ago (STL is an example of policy based design for some degree), it is just recently become essential programming technique. As compilers become more standards compliant, policies become ample part of any class design. I would refer to [Alexandrescu] for discussion about policies. Here I will just walk through the policies mainly for introducing the sample code and demonstrating the benefits of proposed methods.
Suppose we are designing some ImageFile class. The class reads from a file, decodes the picture, and provides some convenient way for accessing its pixels. There is a place for several policies for such class.
The essential policy of almost any class is ErrorPolicy. Error policy can define whether ImageFile should throw an exception or just return a humble false. The programmer might want ImageFile to keep the text describing the error or just an error code or provide some custom error handler, which will log the error, send e-mail, connect through pipe, etc.
ThreadingPolicy is also important in today's multithreaded world. There is no reason to lock/unlock some mutex, if the class is used only from a single thread even in a multithreaded program. From the other side it is very convenient to use the same class from the different threads and not to worry about coordinating the access to that class manually. Once you start making mutexes around somebody's classes, then get ready to many nasty things like deadlocks, thread leeks, etc. The best solution is to tell the class what you think about the threading model and let it do the whole job.
Among other policies would be MemoryAllocatorPolicy, just like STL's allocator. StringPolicy could also help, to choose whether the class should use std::string or something custom made. On the edge of 32-64 bit computing LargeFilePolicy could be handy.
ImageFile class should be able to support many formats and have possibility for adding or removing them. This also can be done through the proposed policy mechanism. In this case the policy itself is a container of all supported image formats - ImageFormatContainer.
ImageFile class reads the image from file, but nobody says that it should read only from a local file. It is very convenient to be able to read the data from various ftp, http, and other *tp servers. FileMediaContainer could be the policy containing all the supported data sources.
The definition of ImageFile class would look like this.
template < class ErrorPT = DefErrorP, class ThreadPT = DefThreadP, class AllocPT = DefAllocP, class LargePT = DefLargeP, class FormatCT = DefFormatC, class SourceCT = DefSourceC > class ImageFile { ... } ;
In the simplest case with all default parameters ImageFile class can be used like this:
ImageFile<> nice_file ;
If you want to change the error policy, then just write
ImageFile<MyErrorHandler> ok_file ;
The first inconvenience comes when you need to change a policy, which is not the first on the template parameter list. In this case you have to provide the default values for all the previous arguments.
ImageFile < DefErrorP, DefThreadP, DefLargeP, MyMemoryAllocator > ugly_file ;
It is often suggested to use the following construction:
typedef ImageFile < DefaultErrorHandler, DefaultThreadingModel, MyMemoryAllocator > ugly_file_type ; ugly_file_type better_file ;
In this case you have to type an extra line of code for typedef. Usually the program contains many classes, so you have to typedef every class. Another inconvenience with typedefs is that you usually don't know how much deep into blocks you want to bury them. If typedefs are too deep in your nested blocks, then you have to typedef too often for the same class for different blocks. If you make them too visible, then you won't be able to use nice short names, since there will be several string_type's, value_type's, and connection_type's all around your code.
Inconvenience of providing policies is just a fraction of the bigger problem. If you will decide to add, remove or replace some policy, then you will have to change each use of this class in each application. If the project is big enough, then that kind of modifications become simply impossible. I don't even mention the case when the class is popular and widely used.
Copyright (C) 2005,2006,2013 Andre Mirzoyan