Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
B.Eckel - Thinking in C++, Vol.2, 2nd edition.pdf
Скачиваний:
50
Добавлен:
08.05.2013
Размер:
2.09 Mб
Скачать

} ///:~

TrashBinSet encapsulates all of the different types of TypedBins, along with the sortIntoBins( ) member function, which is where all the double dispatching takes place. You can see that once the structure is set up, sorting into the various TypedBins is remarkably easy. In addition, the efficiency of two virtual calls and the double dispatch is probably better than any other way you could sort.

Notice the ease of use of this system in main( ), as well as the complete independence of any specific type information within main( ). All other methods that talk only to the Trash baseclass interface will be equally invulnerable to changes in Trash types.

The changes necessary to add a new type are relatively isolated: you inherit the new type of Trash with its addToBin( ) member function, then make a small modification to TypedBin, and finally you add a new type into the vector in TrashBinSet and modify

DDTrashPrototypeInit.cpp.

Applying the visitor pattern

Now consider applying a design pattern with an entirely different goal to the trash-sorting problem. As demonstrated earlier in this chapter, the visitor pattern’s goal is to allow the addition of new polymorphic operations to a frozen inheritance hierarchy.

For this pattern, we are no longer concerned with optimizing the addition of new types of Trash to the system. Indeed, this pattern makes adding a new type of Trash more complicated. It looks like this:

Trash

 

 

Visitor

accept(Visitor&);

 

 

visit(Aluminum*);

 

 

 

 

visit(Paper*);

 

 

 

 

visit(Glass*);

 

 

 

 

 

 

 

 

visit(Cardboard*);

Aluminum

 

 

 

accept(Visitor& v){

 

 

v.visit(this);

 

 

 

PriceVisitor

}

 

 

 

 

 

 

visit(Aluminum*){

 

 

 

 

 

 

 

 

// Aluminum-

 

 

 

 

 

 

 

 

// specific work

 

 

 

 

}

 

 

 

 

visit(Paper*) {

 

 

 

 

// Paper-

 

 

 

 

// specific work

 

 

 

 

}

 

 

 

 

 

Chapter 16: Design Patterns

497

Trash

 

 

 

 

 

 

 

 

Visitor

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

accept(Visitor)

 

 

 

 

 

 

 

 

Visit(Aluminum)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Visit(Paper)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Visit(Glass)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Paper

 

 

Glass

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

WeightVisitor

 

 

etc.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Aluminum

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

accept(Visitor v) {

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

PriceVisitor

 

 

 

 

v.visit(this);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

visit(Aluminum) {

 

 

 

}

 

 

 

 

 

 

 

 

 

 

// Perform Aluminum-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

// specific work

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

visit(Paper) {

 

 

 

 

 

 

 

 

 

 

 

 

 

 

// Perform Paper-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

// specific work

 

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

Now, if t is a Trash pointer to an Aluminum object, the code:

PriceVisitor pv; t->accept(pv);

causes two polymorphic member function calls: the first one to select Aluminum’s version of accept( ), and the second one within accept( ) when the specific version of visit( ) is called dynamically using the base-class Visitor pointer v.

This configuration means that new functionality can be added to the system in the form of new subclasses of Visitor. The Trash hierarchy doesn’t need to be touched. This is the prime benefit of the visitor pattern: you can add new polymorphic functionality to a class hierarchy without touching that hierarchy (once the accept( ) methods have been installed). Note that the benefit is helpful here but not exactly what we started out to accomplish, so at first blush you might decide that this isn’t the desired solution.

But look at one thing that’s been accomplished: the visitor solution avoids sorting from the master Trash sequence into individual typed sequences. Thus, you can leave everything in the single master sequence and simply pass through that sequence using the appropriate visitor to accomplish the goal. Although this behavior seems to be a side effect of visitor, it does give us what we want (avoiding RTTI).

The double dispatching in the visitor pattern takes care of determining both the type of Trash and the type of Visitor. In the following example, there are two implementations of Visitor:

Chapter 16: Design Patterns

498

PriceVisitor to both determine and sum the price, and WeightVisitor to keep track of the weights.

You can see all of this implemented in the new, improved version of the recycling program. As with DoubleDispatch.cpp, the Trash class has had an extra member function stub (accept( )) inserted in it to allow for this example.

Since there’s nothing concrete in the Visitor base class, it can be created as an interface:

//: C09:Visitor.h

//The base interface for visitors

//and template for visitable Trash types #ifndef VISITOR_H

#define VISITOR_H #include "Trash.h" #include "Aluminum.h" #include "Paper.h" #include "Glass.h" #include "Cardboard.h"

class Visitor { public:

virtual void visit(Aluminum* a) = 0; virtual void visit(Paper* p) = 0; virtual void visit(Glass* g) = 0; virtual void visit(Cardboard* c) = 0;

};

//Template to generate visitable

//trash types by inheriting from originals: template<class TrashType>

class Visitable : public TrashType { protected:

Visitable () : TrashType(0) {} friend class TrashPrototypeInit;

public:

Visitable(double wt) : TrashType(wt) {}

//Remember "this" is pointer to current type: void accept(Visitor& v) { v.visit(this); }

//Override clone() to create this new type: Trash* clone(const Trash::Info& info) {

return new Visitable(info.data());

}

};

#endif // VISITOR_H ///:~

Chapter 16: Design Patterns

499

As before, a different version of the initialization file is necessary:

//: C09:VisitorTrashPrototypeInit.cpp {O} #include "Visitor.h"

std::vector<Trash*> Trash::prototypes;

class TrashPrototypeInit { Visitable<Aluminum> a; Visitable<Paper> p; Visitable<Glass> g; Visitable<Cardboard> c; TrashPrototypeInit() {

Trash::prototypes.push_back(&a); Trash::prototypes.push_back(&p); Trash::prototypes.push_back(&g); Trash::prototypes.push_back(&c);

}

static TrashPrototypeInit singleton;

};

TrashPrototypeInit

TrashPrototypeInit::singleton; ///:~

The rest of the program creates specific Visitor types and sends them through a single list of Trash objects:

//: C09:TrashVisitor.cpp

//{L} VisitorTrashPrototypeInit //{L} fillBin Trash TrashStatics

//The "visitor" pattern #include "Visitor.h" #include "fillBin.h" #include "../purge.h" #include <iostream> #include <fstream>

using namespace std;

ofstream out("TrashVisitor.out");

//Specific group of algorithms packaged

//in each implementation of Visitor: class PriceVisitor : public Visitor {

double alSum; // Aluminum double pSum; // Paper double gSum; // Glass double cSum; // Cardboard

Chapter 16: Design Patterns

500

public:

void visit(Aluminum* al) {

double v = al->weight() * al->value();

out << "value of Aluminum= " << v << endl; alSum += v;

}

void visit(Paper* p) {

double v = p->weight() * p->value(); out <<

"value of Paper= " << v << endl; pSum += v;

}

void visit(Glass* g) {

double v

= g->weight() * g->value();

out <<

 

"value

of Glass= " << v << endl;

gSum += v;

}

 

void visit(Cardboard* c) {

double v

= c->weight() * c->value();

out <<

 

"value

of Cardboard = " << v << endl;

cSum += v;

}

 

void total(ostream& os) {

os <<

 

"Total

Aluminum: $" << alSum << "\n" <<

"Total

Paper: $" << pSum << "\n" <<

"Total

Glass: $" << gSum << "\n" <<

"Total

Cardboard: $" << cSum << endl;

}

 

};

class WeightVisitor : public Visitor { double alSum; // Aluminum

double pSum; // Paper double gSum; // Glass double cSum; // Cardboard

public:

void visit(Aluminum* al) { alSum += al->weight();

out << "weight of Aluminum = " << al->weight() << endl;

}

Chapter 16: Design Patterns

501

void visit(Paper* p) { pSum += p->weight();

out << "weight of Paper = " << p->weight() << endl;

}

void visit(Glass* g) { gSum += g->weight();

out << "weight of Glass = " << g->weight() << endl;

}

void visit(Cardboard* c) { cSum += c->weight();

out << "weight of Cardboard = " << c->weight() << endl;

}

 

 

void

total(ostream& os) {

os

<< "Total weight

Aluminum:"

 

<< alSum << endl;

 

os

<< "Total weight

Paper:"

 

<< pSum << endl;

 

os

<< "Total weight

Glass:"

 

<< gSum << endl;

 

os

<< "Total weight

Cardboard:"

 

<< cSum << endl;

 

}

 

 

};

int main() { vector<Trash*> bin;

//fillBin() still works, without changes, but

//different objects are prototyped: fillBin("Trash.dat", bin);

//You could even iterate through

//a list of visitors!

PriceVisitor pv; WeightVisitor wv;

vector<Trash*>::iterator it = bin.begin(); while(it != bin.end()) {

(*it)->accept(pv); (*it)->accept(wv); it++;

}

pv.total(out);

wv.total(out);

Chapter 16: Design Patterns

502

Соседние файлы в предмете Численные методы
  • #
    08.05.20133.99 Mб22A.Menezes, P.van Oorschot,S.Vanstone - HANDBOOK OF APPLIED CRYPTOGRAPHY.djvu
  • #
  • #
    08.05.20135.91 Mб24B.Eckel - Thinking in Java, 3rd edition (beta).pdf
  • #
  • #
    08.05.20136.09 Mб17D.MacKay - Information Theory, Inference, and Learning Algorithms.djvu
  • #
    08.05.20133.85 Mб15DIGITAL Visual Fortran ver.5.0 - Programmers Guide to Fortran.djvu
  • #
    08.05.20131.84 Mб12E.A.Lee, P.Varaiya - Structure and Interpretation of Signals and Systems.djvu