Figure 5 - uploaded by Virginia Niculescu
Content may be subject to copyright.
Different features that could be defined for a collection. The features are defined as decoration classes. SpecializedContainer is the base decorator class, which is derived from Storage 

Different features that could be defined for a collection. The features are defined as decoration classes. SpecializedContainer is the base decorator class, which is derived from Storage 

Source publication
Conference Paper
Full-text available
Decorator design pattern is a very well-known pattern that allows additional functionality to be dynamically attached to an object. Decorators provide a flexible alternative to subclassing for extending functionality. In this paper we analyze and design a pattern – MixDecorator – that could be considered an enhanced version of the Decorator pattern...

Context in source publication

Context 1
... storage capability – the elements that are grouped together have to be stored into the memory in an accessible way; usually the term container emphasizes more this aspect; (2) specific behavior – the operations that are allowed for a specific type of container have different specifications; usually the term collection is chosen to emphasize this aspect. Storage capability. The first aspect is directly connected to the data structures used for storing the elements. For storage, we may use a continuous block of memory or a set of discontinues blocks of memory (nodes) connected one to another using links (references). Each container has to be stored in the memory, in a way that allows elements to be added, removed, retrieved, and searched. The storage capability of a collection could be considered as a basic, compulsory, implicit feature, that characterizes any collection[Nic11]. Specialized behavior – specialized containers. The set of operations that could be applied to a container may be different, but also their specification may be different from one collection type to another. In order to emphasize these differences from behavior point of view, we may identify a set of features that could be applied to a container. So, our approach is not based on abstract data types, but on specific behaviors defined with features. This was inspired by feature-oriented programming [BG97, CE00]. The design was leaded by the following main principle: We considered a feature as being a distinctive property that characterizes the behavior of a collection – an operation or a set of operations with defined arguments, together with their semantic, expressed by a clear specification. It is something that fundamentally characterizes the collection behavior [NL13]. Starting from a concrete storage structure we may create different collection types, by adding different behaviors. ¡A behaviour is defined as being formed of a combination of basic features.¿ For example, a set is characterized only by the fact there are no duplicate elements in the container. The feature Unique defines the operation add with the same argument list as in the basic storage type, but changes the postcondition of the operation, by assuring the fact that the argument is added only if its value is not yet present in the container. How these elements are stored, is not a fact that characterizes the set. Sequence assures the fact that the elements are in a particular linear order; the implementation translates this abstract specification into a concrete behavior by offering a bidirectional read and write iterator. Ranked is a feature that specifies an added behavior that allows the access to the elements based on their rank. A rank of an element in a collection is equal to the rank of it in the traversal executed by the implicit iterator. So, this could be added not only to sequences. Stacks and queues specify particular behaviors, and because of that, they could be seen as features. They are specializations of sequences. Many other features could be defined, and this represents the main modality of extending the framework. 4.2. Features classification. The features could be classified depending on how they change the behavior of the container: • features that preserve the default container operations, but changes their specifications; ex. Unique (symmetric features); • features that add new operations; ex. Ranked, Sequence ; • features that restrain the set of operations; ex. UnmodifiableStorage ; • features that restrain the implicit set of operations, but add some other new operations; ex. Stack, Queue – they eliminate remove(elem) , and introduce extract() ; We may identify some restrictions; for example there are features, which could not be added after we have already have some elements into the support container. All these features are specializations of EmptyStorage feature. Generally, between features we may establish specialization/generalization relationships. The first design of the framework was based on Decorator pattern and this forced us to classify the features into levels and impose an order in the possible addition of the features based on these levels. Ranked , for example, adds operations like getElem(index), setElem(val,index) , getRank(val), remove(index) . Using Decorator based design, this should be the last added feature in order to allow these operations to be visible and accessible. Figure 5 shows some decoration classes as they were defined in the Decorator based design. But these constraints are eliminated if MixDecorator pattern is used. Using this new design we can also add Unique after Ranked and all additional operations brought by Ranked are still available. MixDecorator assures the fact that all the additional operations are accessible even if the decoration that defined them is not the last. The modification that we had to apply to the first design was to add a new decorator interface derived from IStorage and a new class FeaturesOperations derived from SpecializedContainer , which defines all the additional operations that the features introduce. The concrete decorations features are derived now from the class FeaturesOperations , and not directly from SpecializedContainer (Figure 6). 4.3. Framework design in more detail. We have considered that: memory representation, iterability, and searchability are implicit properties of each collection type of the framework. Based on these, the IStorage interface is defined as is shown in Figure 7. The class SpecializedContainer defines template methods for the methods of IStorage . These template methods call some proxy methods (initially declared in Storage<T> – Figure 4) that precede and succeed the calls of the actual storage methods. Some dependences could be defined on them (e.g. prev add() and post add() are used by all operations that implies insertion or setting of new values). When we work with a container with several decorations, the proxy methods of the decoration are called in a chain. The symmetric features modify the specifications of some basic storage operations. Prefix proxy operations could modify the preconditions, and suffix proxy operations could modify the postconditions. A decoration that corresponds to a feature that restrains the basic set of features, implements prefix proxy operations that block the execution of the operations that have to be excluded. For example, Unique defines a decoration that assures that no duplicates are included into the container. More precisely it defines the method prev add in such a way that if the element is already into the container, the add operation of the storage support is no longer called. Also, since for the collections, the decorations are dependent on each other, the proxy operations are called also in the recursive process specific to MixDecorator – the process of finding the concrete definition of the method. When methods corresponding to features are defined in the decorator class, besides forwarding the call to the base, prefix and suffix operations are called, too. 4.4. Framework usage. As we have specified before, the framework allows the creation of new collections by adding the characteristic features. We will give few examples. If the user needs a stack of integers, with unique value elements he/she may use the following code: If after using the stack for the initial purpose, based on the LIFO principle, the stack is not empty, the same storage could be used as a simple collection: If for elements which are remained in the collection we would like to have direct access based on the rank, we may add Ranked feature: 5. Conclusions and Future Work The proposed pattern – MixDecorator – is similar to Decorator pattern in the sense that allows functionality extension, but it brings an important advantage by allowing new responsibilities to be added. It treats the situations when we want to add new responsibilities, more concretely, when we want to enlarge the set of messages that could be sent to an object (so we may consider that we dynamically modify the type of an object). Different combinations of these messages could be used, and all the responsibilities are directly accesible. Other important advantages are provided: • IComponent is independent of any decoration declaration, so already defined concrete classes could be used; • it allows a multi-stage development, and so extensions are possible and they benefit of the same advantages as the first defined set of decorations. The implementation constraint of the solution that allows future decoration extensions is related to the fact that we have to be able to add a set of operations to an interface and also to provide a basic implementation for the corresponding methods. This could be achieved by using multiple inheritance, a surrogate of it, as that provided by the Java extended interfaces, or other mechanisms specific to the implementation language – as C# extension methods. As the example with the data structures emphasizes, the applicability of the MixDecoration pattern is clearly defined and brings important advantages over the classical one. The pattern has been used in order to allow the creation of new collections based on dynamic composition of the features that characterize the corresponding data structures. In this way we may add or remove features dynamically. The fact that only linear ...

Citations

... This extension of the interface brings some problems related to the accessibility 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 Decorator pattern named MixDecorator. The implementation of MixDecorator requires (if we want to allow extensibility in time, which means adding new decorations with the same accesibility properties) a form of extension methods mechanism to be existent into the implementation language. ...
... MixDecorator is an enhanced version of Decorator pattern that eliminates some constraints of the classical pattern -most importantly the limitation to initial interface. In the same time, it could also be seen as a general extension mechanism (Niculescu, 2015). ...
... When designing a language, the designer selects the set of reuse mechanisms that best fits the desired characteristics of the language. For example, Java only implements single inheritance, Pharo implements single inheritance and stateless traits, Scala [31] implements single inheritance and Mixins 1 , CLOS [16] implements multiple inheritance and after, around and before methods. ...
... It also implements the Trait concept but only as a variation of mixins. It is intended to prevent the diamond problem[31]. ...
Conference Paper
Code reuse is a good strategy to avoid code duplication and speed up software development. Existing object-oriented programming languages propose different ways of combining existing and new code such as e.g., single inheritance, multiple inheritance, Traits or Mixins. All these mechanisms present advantages and disadvantages and there are situations that require the use of one over the other. To avoid the complexity of implementing a virtual machine (VM), many of these mechanisms are often implemented on top of an existing high-performance VM, originally meant to run a single inheritance object-oriented language. These implementations require thus a mapping between the programming model they propose and the execution model provided by the VM. Moreover, reuse mechanisms are not usually composable, nor it is easy to implement new ones for a given language. In this paper, we propose a modular meta-level runtime architecture to implement and combine different code reuse mechanisms. This architecture supports dynamic combination of several mechanisms without affecting runtime performance in a single inheritance object-oriented VM. It includes moreover a reflective Meta-Object Protocol to query and modify classes using the programming logical model instead of the underlying low-level runtime model. Thanks to this architecture, we implemented Stateful Traits, Mixins, CLOS multiple inheritance, CLOS Standard Method Combinations and Beta prefixing in a modular and composable way.