Online Book Reader

Home Category

Professional C__ - Marc Gregoire [491]

By Root 1293 0
an image, you could temporarily decorate the stream object with an ImageStream object. The ImageStream constructor would take the stream object as a parameter and would have built-in knowledge of image parsing. Once the image is parsed, you could continue using the original object to parse the remainder of the stream. The ImageStream acts as a decorator because it adds new functionality (image parsing) to an existing object (a stream).

Example: Defining Styles in Web Pages

As you may already know, web pages are written in a simple text-based structure called HyperText Markup Language (HTML). In HTML, you can apply styles to a text by using style tags, such as and for bold and and for italic. The following line of HTML will display the message in bold:

A party? For me? Thanks!

The following line will display the message in bold italic:

A party? For me? Thanks!

Assume that you are writing an HTML editing application. Your users will be able to type in paragraphs of text and apply one or more styles to them. You could make each type of paragraph a new subclass, as shown in Figure 29-6, but that design could be cumbersome and would grow exponentially as new styles were added.

FIGURE 29-6

The alternative is to consider styled paragraphs not as types of paragraphs, but as decorated paragraphs. This leads to situations like the one shown in Figure 29-7, where an ItalicParagraph operates on a BoldParagraph, which in turn operates on a Paragraph. The recursive decoration of objects nests the styles in code just as they are nested in HTML.

FIGURE 29-7

Implementation of a Decorator

To decorate the Paragraph class with zero or more styles, you will need a hierarchy of styled Paragraph classes. Each of the styled Paragraph classes will be constructible from an existing Paragraph. This way, they can all decorate a Paragraph or a styled Paragraph. The most convenient way to implement the styled classes is as subclasses of Paragraph. Here is the Paragraph base class:

class Paragraph

{

public:

Paragraph(const string& inInitialText) : mText(inInitialText) {}

virtual string getHTML() const { return mText; }

protected:

string mText;

};

Code snippet from Decorator\Decorator.cpp

The BoldParagraph class will be a subclass of Paragraph so that it can override getHTML(). However, because we intend to use it as a decorator, its only public non-copy constructor takes a const reference to a Paragraph. Note that it passes an empty string to the Paragraph constructor because BoldParagraph doesn’t make use of the mText data member — its only purpose in subclassing Paragraph is to override getHTML().

class BoldParagraph : public Paragraph

{

public:

BoldParagraph(const Paragraph& inParagraph) :

Paragraph(""), mWrapped(inParagraph) {}

virtual string getHTML() const {

return "" + mWrapped.getHTML() + "";

}

protected:

const Paragraph& mWrapped;

};

Code snippet from Decorator\Decorator.cpp

The ItalicParagraph class is almost identical:

class ItalicParagraph : public Paragraph

{

public:

ItalicParagraph(const Paragraph& inParagraph) :

Paragraph(""), mWrapped(inParagraph) {}

virtual string getHTML() const {

return "" + mWrapped.getHTML() + "";

}

protected:

const Paragraph& mWrapped;

};

Code snippet from Decorator\Decorator.cpp

Again, remember that BoldParagraph and ItalicParagraph only subclass Paragraph so that they can override getHTML(). The content of the paragraph comes from the wrapped object, not from the mText data member.

Using a Decorator

From the user’s point of view, the decorator pattern is appealing because it is very easy to apply, and is transparent once applied. The client doesn’t need to know that a decorator has been employed at all. A BoldParagraph behaves just like a Paragraph.

Here is a quick example that creates and outputs a paragraph, first in bold, then in bold and italic:

Paragraph p("A party? For me? Thanks!");

// Bold

cout << BoldParagraph(p).getHTML() << endl;

// Bold and Italic

cout << ItalicParagraph(BoldParagraph(p)).getHTML()

Return Main Page Previous Page Next Page

®Online Book Reader