Decorator

from Wikipedia, the free encyclopedia

The Decorator (also Decorator ) is a design pattern in the field of software development , which the category of structural patterns (engl. Structural patterns ) belongs. The pattern is a flexible alternative to subclassing to add additional functionality to a class . It is a design pattern of the so-called GoF pattern .

use

The instance of a decorator is placed before the class to be decorated. The decorator has the same interface as the class to be decorated. Calls to the decorator are then changed or forwarded unchanged ( delegation ), or they are processed completely independently. The decorator is "invisible" because the caller does not even notice that a decorator is upstream.

Design pattern decorator in UML notation

In an alternative variant, the decorator can be integrated as a strategy and called explicitly.

actors

The abstract component defines the public interface for the objects to be decorated. The concrete component defines objects that can be decorated.

The abstract decorator holds a reference to the abstract component and provides the same interface as the abstract component. The particular decorator defines and implements one or more special decorations.

Advantages and disadvantages

The advantages are that several decorators can be connected in series; the decorators can be swapped out at runtime and even after instantiation. The class to be decorated is not necessarily specified (but its interface is). In addition, long and confusing inheritance hierarchies can be avoided.

The pattern has a danger: Since a decorated component is not identical to the component itself (as an object), care must be taken when testing for object identity. (A comparison can go wrong, although the same component is meant.) In addition, when using decorated components, the messages from the decorator must be forwarded to the decorated object.

Examples

The stream classes of the Java library

The stream classes in the Java library represent one implementation of the decorator pattern. The concrete stream object is decorated with objects that add new properties to the stream and can be further decorated. Decorator objects can be used that add new status information or those that provide new interfaces.

Extending GUI components

A text field should be "decorated" with a frame.

The corresponding decorator object is inserted between the caller and the text field object. The decorator object creates the frame and passes control flow to the text field. Since the decorator has the same interface, nothing changes from the caller's point of view.

Extending the functionality of GUI components

Each component is represented from the point of origin (0, 0); this is the actual class to be decorated. An upstream decorator can shift the position by changing the display and mouse coordinate calls.

One specialization of this is a decorator, which also defines a fixed size, outside of which nothing can be displayed. Another specialization extends the display call by a surrounding frame.

An additional decorator, who decorates the first decorator again, can make the component invisible or switched off by optionally blocking display and mouse query methods.

This example also shows that inheritance and delegation are not mutually exclusive.

An example in C #

In an adventure game there are characters. Any of them can make threats. A specific character is, for example, a monster. Game characters can catch colds and coughs at runtime - then their threats are preceded by a sniff or cough.

The following program example shows how to use the decorator pattern to sniffle and cough up a monster.

What is important is to understand that not the subclasses VerschnupftesMonster , VerhustetesMonster , VerschnupftesVerhustetesMonster and VerhustetesVerschnupftesMonster be formed. This approach would lead to an exponential increase in the number of subclasses if additional attributes such as “insane” and “fire-breathing” were added - not to mention unbearable class names such as coughed-up, sniffed-crazy, fire-breathing monster . Only the (sequences of) decorations that are actually required are created.

You can also see that the client code knows nothing about the decorators after the decorated objects have been created. From the perspective of the client code, the call to threaten is always pawn.Drohe () .

using System;

namespace DekoratorMuster
{

    public abstract class Spielfigur
    {
        public abstract void Drohe();
    }

    public class Monster : Spielfigur
    {
        public override void Drohe()
        {
            Console.WriteLine("Grrrrrrrr.");
        }
    }

    public abstract class Dekorierer : Spielfigur
    {
        private Spielfigur meineFigur;

        public Dekorierer(Spielfigur s)
        {
            meineFigur = s;
        }

        public override void Drohe()
        {
            meineFigur.Drohe();
        }
    }

    public class HustenDekorierer : Dekorierer
    {
        public HustenDekorierer(Spielfigur s)
            : base(s)
        { }

        public override void Drohe()
        {
            Console.Write("Hust, hust. ");
            base.Drohe();
        }
    }

    public class SchnupfenDekorierer : Dekorierer
    {
        public SchnupfenDekorierer(Spielfigur s)
            : base(s)
        { }

        public override void Drohe()
        {
            Console.Write("Schniff. ");
            base.Drohe();
        }
    }

    public class ClientCode
    {
        public static void Main()
        {
            Spielfigur meinMonster = new Monster();
            meinMonster.Drohe();

            Spielfigur meinVerhustetesMonster = new HustenDekorierer(meinMonster);
            meinVerhustetesMonster.Drohe();

            Spielfigur meinVerschnupftesMonster = new SchnupfenDekorierer(meinMonster);
            meinVerschnupftesMonster.Drohe();

            Spielfigur meinVerschnupftesVerhustetesMonster = new SchnupfenDekorierer(new HustenDekorierer(meinMonster));
            meinVerschnupftesVerhustetesMonster.Drohe();

            Spielfigur meinVerhustetesVerschnupftesMonster = new HustenDekorierer(new SchnupfenDekorierer(meinMonster));
            meinVerhustetesVerschnupftesMonster.Drohe();
        }
    }
}

The output of this program is:

Grrrrrrrrr.
Hust, hust. Grrrrrrrrrr.
Schniff. Grrrrrrrrrr.
Schniff. Hust, hust. Grrrrrrrrrr.
Hust, hust. Schniff. Grrrrrrrrrr.

Similarly, examples can be created in C ++ and other object-oriented programming languages.

Related patterns

Compared to the decorator, who chooses the class to be actually used, the calling instance must explicitly know which variants are available and which of them should be used with the strategy pattern.

The composite design pattern is similar to the decorator .

Individual evidence

  1. Erich Gamma , Richard Helm , Ralph Johnson , John Vlissides : Design pattern . 5th edition. Addison-Wesley , 1996, ISBN 3-8273-1862-9 , pp. 199 .