Efficient Decorator Pattern Variants through C++ Policies
Virginia Niculescu
Faculty of Mathematics and Computer Science, Babe¸s-Bolyai University, 1 M. Kogalniceanu, Cluj-Napoca, Romania
Keywords:
Decorator, Patterns, Templates, Policy, Accessibility, Extensibility, Interfaces, C++.
Abstract:
C++ Policies represent an interesting metaprogramming mechanism that allows behavior infusion in a class. In
this paper, we will investigate the possibility of using them for the implementation of some extended Decorator
pattern variants. For the MixDecorator variant, policies are used to simulate extension methods, which are
needed for implementation. Beside this, other two alternatives for Decorator pattern are proposed: one purely
based on inheritance, and another that is a hybrid one; the last one wraps an object with decorations defined
as a linear hierarchy of classes introduced using policies. This is possible since a policy introduces a kind
of recursive definition for inheritance. The advantages and disadvantages of these variants are analyzed on
concrete examples. The hybrid variant presents many important advantages that qualify it as a valid and
efficient Decorator pattern variant – HybridDecorator.
1 INTRODUCTION
C++ Policies could be considered a very interesting
and useful metaprogramming mechanism that allows
behavior infusion in a class through templates and in-
heritance (Alexandrescu, 2001; Abrahams and Gur-
tovoy, 2003). They have been also described as a
compile-time variant of the Strategy pattern. Instead
of parameterizing the class through a strategy object
able to solve a required problem, the solving strat-
egy is introduced through a template parameter from
which the class also is inherited from. In addition,
policies could be very useful as a mean for specifying
implementation of extended interfaces. We intend to
introduce here another interesting usage of the poli-
cies, related to static implementations of Decorator
pattern and its variants.
Decorator and Strategy patterns provide both al-
ternative designs to address problems that involve
changing or extending the objects’ functionalities,
possibly dynamically (Gamma et al., 1994; Pikus,
2019; Shalloway and Trott, 2004). Strategy is a be-
havioral pattern that encapsulates a family of algo-
rithms, and make them interchangeable; it changes
an object from inside. On the other side, Decorator,
classified as fundamental design pattern in (Zimmer,
1995), is considered a structural design pattern; but
since it is used to dynamically attach additional re-
sponsibilities to an object it also affects the behaviour
of that object.
The reason for this investigation is given also by
the fact that static definitions are considered in gen-
eral more optimal since the number of operations to
be executed at the runtime is reduced, but the main
advantage is given by the enhanced functionality. In
the classical definition of Decorator pattern, the ini-
tial object is wrapped with several “decorations” that
not only could change the functionality of the initial
object interface but also, they could enlarge its inter-
face with new methods. This extension of the inter-
face brings some problems related to the accessibil-
ity of the new introduced methods. This have been
analysed in (Niculescu, 2015) and the solution for this
was expressed as a new enhanced variant of the Dec-
orator pattern named MixDecorator. The implemen-
tation of MixDecorator requires (if we want to allow
extensibility in time, which means adding new deco-
rations with the same accesibility properties) a form
of extension methods mechanism to be existent into
the implementation language. Implementation solu-
tions were given for Java through interface default
methods (Oracle, 2018), and in C# through exten-
sion methods (Microsoft Contributors, 2015). Since
in C++ there is not such an extension methods mech-
anism (Stroustrup, 2018), we proposed here a C++
solution based on policies.
The paper also presents other two variants for
Decorator implementation, which could be consid-
ered as compile-time variants of the Decorator pat-
tern. One purely based on inheritance, and another
that is a hybrid one, which wraps an object with deco-
rations that are defined as a linear hierarchy of classes.
Niculescu, V.
Efficient Decorator Pattern Variants through C++ Policies.
DOI: 10.5220/0009342802810288
In Proceedings of the 15th International Conference on Evaluation of Novel Approaches to Software Engineering (ENASE 2020), pages 281-288
ISBN: 978-989-758-421-3
Copyright
c
2020 by SCITEPRESS – Science and Technology Publications, Lda. All rights reserved
281
The paper is structured as follows: Section 2 suc-
cinctly describes what policies means in C++ together
with their applicability. Section 3 presents the classi-
cal Decorator pattern with the associated challenges,
and the MixDecorator solution. In section 3.1 a C++
implementation of the MixDecorator pattern is ex-
plained, and Section 4 analyses the two new proposed
variants of the Decorator pattern. Conclusions and fu-
ture work are presented in section 5.
2 C++ POLICIES
Generally, a policy is defined as a class or class tem-
plate that defines an interface as a service to other
classes (Alexandrescu, 2001). A key feature of the
policy idiom is that, usually, a template class will de-
rive from (make itself a child class of) each of its pol-
icy classes (template parameters).
More specifically, policy based design implies the
creation a template class, taking several type param-
eters as input, which are instantiated with types se-
lected by the user the policy classes, each imple-
menting a particular implicit interface called pol-
icy, and encapsulating some orthogonal (or mostly or-
thogonal) aspect of the behavior of the template class.
Through policies the code is minimized, while
still allowing solutions for specific class related func-
tionalities. In (Alexandrescu, 2001) it is stated that
policy-based class design fosters assembling a class
with complex behavior out of many little classes
(called policies), each of which taking care of only
one behavioral or structural aspect. As the name sug-
gests, a policy establishes an interface pertaining to
a specific issue. It is possible to implement poli-
cies in various ways as long as the policy interface
is respected. Policies have been also described as a
compile-time(static) variant of the Strategy pattern.
For example, if we need to enlarge the capacity
of a container when a new element is added, we can
increase it with one or with half of the existing size
(or other strategies could be used, too). The strategy
will be chosen depending on the specific usage of the
container – Listing 1.
1 t e m p l a t e < c l a s s T >
2 c l a s s i n c r e m e n t E n l a r g e r {
3 p r o t e c t e d :
4 v o i d e n l a r g e ( i n t & c a p a c i t y ) {
5 c a p a c i t y ++ ;
6 }
7 }
8 t e m p l a t e < c l a s s T >
9 c l a s s h a l f E n l a r g e r {
10 p r o t e c t e d :
11 v o i d e n l a r g e ( i n t & c a p a c i t y ) {
12 c a p a c i t y += c a p a c i t y / 2;
13 }
14 }
15 t e m p l a t e < t y p e n a m e E n l a r g e P o l i c y >
16 c l a s s C o n t a i n e r :
17 p r o t e c t e d E n l a r g e P o l i c y {
18 .. .
19 p r o t e c t e d :
20 v o i d d o E n l a r g e () c o n s t {
21 e n l a r g e ( c a p a c i t y ) ;
22 .. .
23 }
24 .. .
25 };
Listing 1: An example of using policies.
Policies have direct connections with C++ template
metaprogramming and they have been used in many
examples; classical examples are: string class, I/O
streams, the standard containers, and iterators (Abra-
hams and Gurtovoy, 2003).
3 DECORATOR PATTERN
In (Gamma et al., 1994) book the Decorator pattern
is described as a pattern that provides a flexible al-
ternative to using inheritance for modifying behavior.
By using it we may add additional functionalities or
change the functionality of an object. This is a struc-
tural design pattern used to extend or alter the func-
tionality of objects by wrapping them into instances
of some decorator classes. Figure 1 presents the struc-
ture of its solution. It is generally agreed that deco-
rators and the original class object share a common
interface, and different decorators can be stacked on
top of each other, each time adding new functionality
to the overridden method(s).
Still, there are many situations when the decora-
tors need to add also new methods (i.e. methods that
are not in the initial object interface) that bring addi-
tional behavior; a very well known example is rep-
resented by the Java decorator classes for input and
output streams.
Since the interface IComponent defines only the
initial set of operations, the new added methods are
accessible only if they belongs to the last added dec-
orator, and the object is used through a reference of
that decorator type.
Also, removing and adding decorations at the run-
ning time is a requirement stated into the classical
pattern definition. Adding decorations is not difficult,
since they could be added on top. If we understand by
removing decorations that we can remove the top dec-
oration, then this is only possible if a method that re-
ENASE 2020 - 15th International Conference on Evaluation of Novel Approaches to Software Engineering
282
Figure 1: The Class Diagram of the Classical decorator Pat-
tern.
turns the wrapped object is defined in the IDecorator
interface (e.g. getBase()). But if we would like to
remove a decoration, which is in the middle of the
decoration chain, this is not a trivial task.
3.1 MixDecorator Pattern with Policies
MixDecorator is an enhanced version of Decorator
pattern that eliminates some constraints of the classi-
cal pattern – most importantly the limitation to initial
interface. In the same time, it could also be seen as a
general extension mechanism (Niculescu, 2015).
The structure of the MixDecorator is similar to
that of the classical Decorator pattern but with some
important differences. Figure 2 shows the UML class
diagram of the MixDecorator solution.
Figure 2: The Class Diagram of the MixDecorator Pattern.
As for the classical decorators, the subject (a con-
crete component) is enclosed into another object a
decorator object, but the decorator has an interface
that could extend the general component interface.
This means that the decorators could define new pub-
lic methods, which could be refered to as interface-
responsibilities.
In addition to the classical Decorator struc-
ture, there is a special class Operations, which de-
fines methods that correspond to all new interface-
responsibilities defined in all decorators. As it can
be seen from Figure 2, the concrete decorator classes
Decorator1, Decorator2 are derived from Decorator
but also from Operations. The implementation of an
Operations method hides a recursion that tries to call
the method with the same name from the enclosed ob-
ject, and if this is not available, it goes further to the
previous decoration. The recursion stops either when
the concrete method is found or when it arrives to an
undecorated component.
Another possible variant would be to consider
Operations as a class derived from Decorator, and
then all concrete decorators extend only Operations
class the problem with this approach is related to
the difficulties in extending the set of newly added
interface-responsibilities.
For a particular application/framework, after the
new interface-responsibilities are inventoried, then a
particular class Operations could be defined. But, in
time, it is possible that new decorators with new meth-
ods are required to be defined. For example, consid-
ering the diagram presented in Figure 2 it would be
possible to introduce a new decorator Decorator3
that defines a new method f3; this requires an exten-
sion of the class Operations OperationsExtended
that defines the method f3(), as well. The integration
of this kind of extension of the Operations class rep-
resents the implementation challenge of the MixDec-
orator pattern.
1 t e m p l a t e < t y p e n a m e B >
2 c l a s s D e c o r a t o r : p u b l i c B
3 {
4 p r o t e c t e d :
5 I C o m p o n e n t * c ;
6 p u b l i c :
7 D e c o r a t o r ( I C o m p o n e n t * c ) {
8 t h i s -> c = c ;
9 }
10 I C o m p o n e n t * g e t B a s e () {
11 r e t u r n c ;
12 }
13 v o i d o p e r a t i o n () {
14 c - > o p e r a t i o n () ;
15 }
16 };
Listing 2: Decorator class definition based on a policy.
A simple extension through inheritance of the
Operations interface that will be implemented by the
Efficient Decorator Pattern Variants through C++ Policies
283
new decorators is not enough since we also have to al-
low direct access to all responsibilities independently
of the order in which decorators are added. If, for ex-
ample, a previously defined decorator is added on top,
the new added responsibilities would not be accessi-
ble. In Java, or C# we may use default interface meth-
ods, respectively extension methods, to overcome this
requirement.
Because in C++ it is not possible to define exten-
sion methods or other similar mechanisms, a solution
is to use policies in order to postpone the specification
of the parent class for decorators.
The Decorator class is defined as a template class,
and the template parameter is also used as a parent
class for the Decorator class Listing 2. The class
Operations is needed to be defined as a parent class
of the Decorator class, but this relation will be defined
through the template parameter. The policy that is in-
troduced this way specifies which kind of Operations
to be used. So, we may postpone the specification
of the base class, and allow this base to be either
Operations or OperationsExtended.
1 t e m p l a t e < t y p e n a m e B >
2 c l a s s D e c o r a t o r 1 : p u b l i c D e c o r a t o r < B >
3 {
4 p u b l i c :
5 D e c o r a t o r 1 ( I C o m p o n e n t * c ) :
6 D e c o r a t o r < B >( c ) { }
7 v i r t u a l v o i d f 1 () {
8 c o u t << " f 1 " << e n d l ;
9 }
10 };
Listing 3: An example of a concrete Decorator
implementation.
The concrete decorators are also defined as
template classes, since they are derived from the
Decorator class Listing 3 presents the implemen-
tation for Decorator1.
1 c l a s s O p e r a t i o n s : p u b l i c I C o m p o n e n t ,
2 p u b l i c I D e c o r a t o r
3 {
4 p u b l i c :
5 O p e r a t i o n s () { }
6 v i r t u a l v o i d f 1 () {
7 I C o m p o n e n t * c = g e t B a s e () ;
8 O p e r a t i o n s * d c =
9 s t a t i c _ c a s t < O p e r a t i o n s * >( c );
10 i f ( d c != N U L L ) d c -> f 3 () ;
11 }
12 v i r t u a l v o i d f 2 () {
13 / / s i m i l a r t o f 1
14 }
15 };
Listing 4: Operations class in C++ implementation.
The class Operations implements the IDecorator
interface and defines the corresponding searching
methods for the newly defined methods in the con-
crete decorators (Listing 4).
The Decorator class inherits IComponent and
IDecorator through Operations class. (By letting
Decorator to specify directly the inheritance from
IComponent and IDecorator then virtual inheritance
would be needed, and in this case static_cast should
be replaced with dynamic_cast.)
The class Operations could be extended with classes
that define new methods that corresponds to the new
responsibilities added into additional decorators. For
example, if we have a new decorator Decorator3
that defines a new method f3(), than a new class
OperationsExtended that extends Operations is de-
fined, and when using this new decorator we need
to specify OperationsExtended as a parameter for
Decorator (Listing 5).
1 c l a s s O p e r a t i o n s E x t e n d e d :
2 p u b l i c O p e r a t i o n s
3 {
4 p u b l i c :
5 O p e r a t i o n s E x t e n d e d () { }
6 v i r t u a l v o i d f 3 () {
7 I C o m p o n e n t * c = g e t B a s e () ;
8 O p e r a t i o n s E x t e n d e d * d c =
9 s t a t i c _ c a s t < O p e r a t i o n s E x t e n d e d * >( c );
10 i f ( d c != N U L L ) d c - > f 3 ();
11 }
12 };
Listing 5: Extending the Operations class in C++
implementation.
1 v o i d m a i n () {
2 I C o m p o n e n t * c =
3 n e w C o n c r e t e C o m p o n e n t () ;
4 D e c o r a t o r < O p e r a t i o n s > * d c =
5 n e w D e c o r a t o r 1 < O p e r a t i o n s >( c ) ;
6 d c -> f 1 () ;
7 D e c o r a t o r < O p e r a t i o n s E x t e n d e d >*
8 d c 1 3 =
9 n e w D e c o r a t o r 1 < O p e r a t i o n s E x t e n d e d >(
10 n e w D e c o r a t o r 3 < O p e r a t i o n s E x t e n d e d > -
( c ) ) ;
11 d c 1 3 -> f 3 () ;
12 d c 1 3 -> f 1 () ;
13 d c 1 3 -> o p e r a t i o n ()
14 }
Listing 6: Testing different methods’ calls in C++
implementation.
The example in Listing 6 shows first a decora-
tion with Decorator1 (for which the class Operations
is enough to be used), and then Decorator3 is
added (for which we have the correspondent class
OperationsExtended). Since OperationsExtended ex-
ENASE 2020 - 15th International Conference on Evaluation of Novel Approaches to Software Engineering
284
tends Operations the function f3() could be called
even after Decorator1 was added.
Because the template instantiation leads to the cre-
ation of a new class this is a statical efficient approach.
4 DECORATOR VARIANTS
BASED ON POLICIES
The principal intent of the Decorator pattern is to
avoid the class explosion when there are many com-
bination of a set of functionalities/responsibilities.
In the classical Decorator definition, composition
is used instead of inheritance as a mean of avoiding
the class explosion; but if we can avoid this explo-
sion while still using inheritance, this should not be
excluded.
In order to better explain the proposed solutions,
and also to link to a real example, we will consider a
concrete example on which we will analyze the pos-
sibilities to define a kind of Decorator based on tem-
plate inheritance.
Case Study: [ReaderDecorator]. We consider a
case when we intend to define text analyzer decora-
tions, which decorate a Reader (an object that could
retrieve from a text stream, a single character, an en-
tire line, or a specified number of characters). There
are examples of such readers in Java and also in C# -
(Java: the class Reader; C# - the class StreamReader).
The basic method of the Reader is readChar() that
extracts a character from the associated stream and
returns it. Some basic decorations that could be pro-
vided are:
1. CharDecorator – a decoration that is able to count
the number of already read characters; this defines
an attribute no_of_chars that will be updated by
the overridden readChar() method, and defines
a method getNoChars() that returns the value of
no_of_chars.
2. WordDecorator a decoration oriented to words
that provides a method getNoWords() that returns
the number of already read words) (optionally the
class could stores all the read words into an inter-
nal list, which could be returned).
3. SentenceDecorator a decoration oriented to sen-
tences that provides a method getNoSentence()
(optionally the class could stores all the read sen-
tences into an internal list, which could be re-
turned).
We will consider a general IReader interface that
defines a method readChar(), and a concrete class
StringReader that uses strings as sources. For other
types of sources, correspondent IReader specializa-
Figure 3: The Class Diagram of the Template Inheritance
Solution Applied to Reader Problem.
tions could be defined. The use of decorations is ap-
propriate since if we do not need to read or count sen-
tences, we don’t have to add the SentenceDecorator,
and similarly for WordDecorator, or CharDecorator.
When needed, other decorations could be added:
counting the number of proper nouns, the number of
non-blank characters, the number of sections, chap-
ters, etc.
4.1 Inheritance based Solution
The simplest way to assure the possibility to create an
object that offers any combination of the three respon-
sibilities enumerated before is to create three template
classes that are derived from their template parameter.
* This means that each decorator is defined using a
policy that should be either a IReader or other
decorator.
1 t e m p l a t e < t y p e n a m e T >
2 c l a s s C h a r R e a d e r : p u b l i c T {
3 p r i v a t e : i n t n o _ o f _ c h a r s ;
4 p u b l i c :
5 C h a r R e a d e r ( s t d :: s t r i n g r ) : T ( r ) {
6 n o _ o f _ c h a r s =0;
7 };
8 c h a r r e a d C h a r () {
9 c h a r c = T :: r e a d C h a r () ;
10 i f ( c !=0) n o _ o f _ c h a r s + +;
11 r e t u r n c ;
12 }
13 i n t g e t N o C h a r s () {
14 r e t u r n n o _ o f _ c h a r s ;
15 }
16 }
Listing 7: Inheritance based solution Definition of
CharReader class.
In this way, a recursive composition of the decorators
is possible. Even if there is no explicit constraint re-
garding the template type, it is implicitly assured that
Efficient Decorator Pattern Variants through C++ Policies
285
1 C h a r R e a d e r <
2 S e n t e n c e R e a d e r <
3 W o r d R e a d e r < S t r i n g R e a d e r > > > * w r =
4 n e w
5 C h a r R e a d e r <
6 S e n t e n c e R e a d e r <
7 W o r d R e a d e r < S t r i n g R e a d e r > > >
8 ( " H a p p y B i r t h d a y ! " ) ;
9
10 w h i l e (( c = w r -> r e a d C h a r () ) != 0)
11 c o u t < < c ;
12
13 c o u t < < w r - > g e t N o W o r d s () < < e n d l ;
14 c o u t < < w r - > g e t N o C h a r s () < < e n d l ;
15 c o u t < < w r - > g e t N o S e n t e n c e s () < < e n d l ;
Listing 8: Inheritance based solution – Usage example.
a class of IReader type (e.g. StringReader) will be
the last in the chain, since it is not generic.
The associated diagram, shown in the Figure 3,
does not emphasizes any relation between the classes.
They will be connected only when concrete examples
are created.
Listing 8 shows a usage example. In the usage
example, all three decorators are added (the order has
no importance), but depending on the needs only one,
or a combination of two could be used.
This solution based only on inheritance (without
composition) has advantages, but also some disadvan-
tages:
Advantages:
only classes for the needed combinations are cre-
ated;
all new defined methods in different decorators
are accessible;
the solution is very simple,
static class creation assures efficiency.
Disadvantages:
for each specialization of IReader, new classes
should be defined for each particular combination
of decorators. If FileReader is a basic reader
with a text file as a source, in order to use an
instance similar to that defined in the previous
usage example then another distinct class should
be defined as:
1 C h a r R e a d e r <
2 S e n t e n c e R e a d e r <
3 W o r d R e a d e r < F i l e R e a d e r >>>
the combination of functionalities could not be
changed during the source traversal;
the decorations could not be dynamically add or
retrived.
Figure 4: The Class Diagram of the HybridDecorator Pat-
tern Applied to the Reader Problem.
4.2 Hybrid Solution – HybridDecorator
A hybrid solution that uses both inheritance and com-
position could be defined. This preserves the basic
object wrapping, but the decorations will be defined
as a single class obtained through a chain of inheri-
tance derivation. In order to assure this, we need to
define a class ExtReader that provides the support for
composition, but in the same time, intermediates the
decorations inheritance.
1 t e m p l a t e < t y p e n a m e T = I R e a d e r >
2 c l a s s E x t R e a d e r : p u b l i c T ,
3 p u b l i c I D e c o R e a d e r , p u b l i c I R e a d e r
4 {
5 p r o t e c t e d :
6 I R e a d e r * b a s e ;
7 p u b l i c :
8 E x t R e a d e r ( I R e a d e r * r ) : T ( r ) {
9 t h i s - > b a s e = r ;
10 }
11 c h a r r e a d C h a r () {
12 r e t u r n T :: r e a d C h a r () ;
13 }
14 I R e a d e r * g e t B a s e () {
15 r e t u r n T :: g e t B a s e () ;
16 }
17 };
Listing 9: The definition of the class ExtReader for the
general parameter value.
The class is defined for the following two cases:
- the basic case with the template parameter equal to
IReader,
- the general case with a general template parame-
ter(T)
ENASE 2020 - 15th International Conference on Evaluation of Novel Approaches to Software Engineering
286
The definitions for these two cases are different, and
the difference is related to the call of the overridden
method readChar():
- for the basic case the call is sent to the wrapped
object (base);
- for the general case the call is sent up to the super-
class – T.
Listing 9 presents the implementation the class
ExtReader for the general template parameter case,
and Listing 10 presents the implementation of the
ExtReader for the implicit case when the template pa-
rameter is IReader.
1 t e m p l a t e <>
2 c l a s s E x t R e a d e r < I R e a d e r >:
3 p u b l i c I R e a d e r , p u b l i c I D e c o R e a d e r
4 p r o t e c t e d :
5 I R e a d e r * b a s e ;
6 p u b l i c :
7 E x t R e a d e r ( I R e a d e r * r ) {
8 t h i s -> b a s e = r ;
9 }
10 c h a r r e a d C h a r () {
11 r e t u r n b a s e - > r e a d C h a r ();
12 }
13 I R e a d e r * g e t B a s e () {
14 r e t u r n b a s e ;
15 }
16 };
Listing 10: The definition of the class ExtReader for the
implicit parameter value (IReader).
1 t e m p l a t e < t y p e n a m e T = I R e a d e r >
2 c l a s s C h a r R e a d e r : p u b l i c E x t R e a d e r < T >
3 {
4 p r i v a t e :
5 i n t n o _ o f _ c h a r s ;
6 p u b l i c :
7 C h a r R e a d e r ( I R e a d e r * r ):
8 E x t R e a d e r < T >( r ) {
9 E x t R e a d e r < T >:: b a s e = r ;
10 n o _ o f _ c h a r s =0;
11 }
12 c h a r r e a d C h a r () {
13 c h a r c = E x t R e a d e r < T >:: r e a d C h a r ();
14 i f ( c ! =0) n o _ o f _ c h a r s ++;
15 r e t u r n c ;
16 }
17 i n t g e t N o C h a r s () {
18 r e t u r n n o _ o f _ c h a r s ;
19 }
20 };
Listing 11: CharReader class definition.
For the concrete decorators, which are extended
from ExtReader, there is no need to explicitly de-
fine the class for the implicit value of the parameter;
this is solved through the ExtReader definition. List-
ing 11 shows the definition of the CharReader class.
WordReader and SentenceReader have similar defini-
tions.
The associated UML diagram for this hybrid im-
plementation is shown in Figure 4. The interface
IDecoReader is similar to the interface IDecorator,
and it just defines the method getBase().
A usage example based on this solution is given
in the Listing 12: a reader associated to a string
source is decorated with CharReader, WordReader, and
SentenceReader in order to allow the counting of
the read characters, words and sentences. It can be
noticed that the usage is very similar to the classi-
cal Decorator implementation, but composition is re-
placed with the template parameter specification.
1 S t r i n g R e a d e r * r =
2 n e w S t r i n g R e a d e r ( " H a p p y B i r t h d a y ! " );
3
4 S e n t e n c e R e a d e r <
5 C h a r R e a d e r <
6 W o r d R e a d e r < > > > * w r =
7 n e w S e n t e n c e R e a d e r <
8 C h a r R e a d e r <
9 W o r d R e a d e r < > > >( r );
10
11 w h i l e (( c = w r -> r e a d C h a r ()) != 0)
12 c o u t << c ;
13
14 c o u t << w r - > g e t N o W o r d s () << e n d l ;
15 c o u t << w r - > g e t N o C h a r s () << e n d l ;
16 c o u t << w r - > g e t N o S e n t e n c e s () << e n d l ;
Listing 12: Hybrid solution – Usage example.
Advantages of the hybrid solution:
only the classes for the needed combinations are
created;
all new defined methods in different decorators
are accessible;
the combination of functionalities could be
changed during the source traversal the basic ob-
ject is retrieved (through the method getBase()),
and then it could be passed to another combina-
tion of functionalities.
for all the specializations of IReader only one par-
ticular class that corresponds to a particular func-
tionality combination could be used;
in order to add a new decoration a new ob-
ject wrapping (similar to the classical Decorator)
could be done the wrapping will specify a new
class with the desired decoration.
static class creation assures efficiency.
Disadvantages:
The decorations could not be dynamically re-
trieved;
Based on the advantages that this solution offers, we
may consider that it represents a valid and efficient
Efficient Decorator Pattern Variants through C++ Policies
287
Figure 5: The Class Diagram of the HybridDecorator Pat-
tern - The General Solution.
Decorator variant HybridDecorator. The general
structure of this is presented in the Figure 5. If
we compare the structure diagram of the MixDec-
orator (Figure 2) and the HybridDecorator struc-
ture diagram, we may notice that even HybridDec-
orator assures full accesibility of all new interface-
responsibilities, it is not necessary to define another
special class Operations to assure this.
5 CONCLUSIONS
The paper analyzes policy based C++ implementa-
tions of the Decorator pattern. Since the classical
Decorator has an accessibility problem if new respon-
sibilities are added to the interface, MixDecorator is
an alternative that solves this problem. But its imple-
mentation (in the extensible mode) requires some lan-
guage mechanisms that allow interface extension (or
extension methods). For MixDecorator C++ imple-
mentation, we have shown how the template policies
could be used as a mean for defining new interfaces,
and in fact to cover the need for extension methods.
Template policies are proposed to be also used
for defining other alternative solutions of the Deco-
rator pattern. Both of the two proposed variants as-
sure complete accessibility over new defined methods
(since inheritance is used for decorations). The Hy-
bridDecorator has a higher degree of reusability, and
it also offers the advantages of the MixDecorator re-
lated to accessibility (so more than the classical Dec-
orator) but with a simpler structure.
The implementation of the MixDecorator pattern
preserves the characteristics of the classical Decora-
tor pattern regarding the possibility to dynamically
remove or add decorations. Also, for the HybridDec-
orator we have the possibility to add decoration, since
the initial decorated object could be wrapped into a
new decoration, similarly defined.
In the Decorator pattern definition is it stated that
the composition is a good alternative to inheritance.
The presented solutions that are based on policies are
implicitly based on inheritance, but the idea that in-
heritance should be avoided was in the context of us-
ing inheritance for creating all possible combinations
- and this is not the case for the policy solution. The
recursion implicitly involved by the templates poli-
cies fits very well to the recursion implied by the Dec-
orator definition.
REFERENCES
Abrahams, D. and Gurtovoy, A. (2003). C++ Template
Metaprogramming: Concepts, Tools, and Techniques
from Boost and Beyond. Addison-Wesley.
Alexandrescu, A. (2001). Modern C++ design: generic
programming and design patterns applied.
Gamma, E., Helm, R., Johnson, R., and Vlissides, J. (1994).
Design Patterns: Elements of Reusable Object Ori-
ented Software. Addison Wesley.
Microsoft Contributors (2015). Extension methods
(C# programming guide). [online: https://msdn.
microsoft.com/en-us/library/bb383977.aspx]. [Ac-
cessed: 07.20.19].
Niculescu, V. (2015). Mixdecorator: An enhanced version
of decorator pattern. In Proceedings of the 20th Eu-
ropean Conference on Languages of Programs, Euro-
PLoP ’15, pages 36:1–36:12, New York, USA. ACM.
Oracle (2018). JAVA SE 8: Default methods. [online: https:
//docs.oracle.com/javase/tutorial/java/IandI/]. [Ac-
cessed:07.20.19].
Pikus, F. G. (2019). Hands-On Design Patterns with C++:
Solve common C++ problems with modern design
patterns and build robust applications. Packt Publ.
Shalloway, A. and Trott, J. R. (2004). Design Patterns Ex-
plained: A New Perspective on Object Oriented De-
sign, 2nd Edition. Addison Wesley.
Stroustrup, B. (2018). A Tour of C++ (2nd Edition) (C++
In-Depth Series). Addison-Wesley Professional.
Zimmer, W. (1995). Relationships between Design Pat-
terns, page 345–364. ACM Press/Addison-Wesley
Publishing Co., USA.
ENASE 2020 - 15th International Conference on Evaluation of Novel Approaches to Software Engineering
288