📄 chap11.htm
字号:
<font color=#0000ff>void</font> <font color=#0000ff>operator</font>--(<font color=#0000ff>int</font>) { count--; }
};
<font color=#0000ff>class</font> BicyclePart {
<font color=#0000ff>static</font> LeakChecker lc;
<font color=#0000ff>public</font>:
BicyclePart() { lc++; }
<font color=#0000ff>virtual</font> BicyclePart* clone() = 0;
<font color=#0000ff>virtual</font> ~BicyclePart() { lc--; }
<font color=#0000ff>friend</font> std::ostream&
<font color=#0000ff>operator</font><<(std::ostream& os, BicyclePart* bp) {
<font color=#0000ff>return</font> os << <font color=#0000ff>typeid</font>(*bp).name();
}
<font color=#0000ff>friend</font> <font color=#0000ff>class</font> Bicycle;
};
<font color=#0000ff>enum</font> BPart {
Frame, Wheel, Seat, HandleBar,
Sprocket, Deraileur,
};
<font color=#0000ff>template</font><BPart id>
<font color=#0000ff>class</font> Part : <font color=#0000ff>public</font> BicyclePart {
<font color=#0000ff>public</font>:
BicyclePart* clone() { <font color=#0000ff>return</font> <font color=#0000ff>new</font> Part<id>; }
};
<font color=#0000ff>class</font> Bicycle {
<font color=#0000ff>public</font>:
<font color=#0000ff>typedef</font> std::vector<BicyclePart*> VBP;
Bicycle();
Bicycle(<font color=#0000ff>const</font> Bicycle& old);
Bicycle& <font color=#0000ff>operator</font>=(<font color=#0000ff>const</font> Bicycle& old);
<font color=#009900>// [Other operators as needed go here:]</font>
<font color=#009900>// [...]</font>
<font color=#009900>// [...]</font>
~Bicycle() { purge(); }
<font color=#009900>// So you can change parts on a bike (but be </font>
<font color=#009900>// careful: you must clean up any objects you</font>
<font color=#009900>// remove from the bicycle!)</font>
VBP& bikeParts() { <font color=#0000ff>return</font> parts; }
<font color=#0000ff>friend</font> std::ostream&
<font color=#0000ff>operator</font><<(std::ostream& os, Bicycle* b);
<font color=#0000ff>static</font> <font color=#0000ff>void</font> print(std::vector<Bicycle*>& vb,
std::ostream& os = std::cout);
<font color=#0000ff>private</font>:
<font color=#0000ff>static</font> <font color=#0000ff>int</font> counter;
<font color=#0000ff>int</font> id;
VBP parts;
<font color=#0000ff>void</font> purge();
};
<font color=#009900>// Both the Bicycle and the generator should </font>
<font color=#009900>// provide more variety than this. But this gives</font>
<font color=#009900>// you the idea.</font>
<font color=#0000ff>struct</font> BicycleGenerator {
Bicycle* <font color=#0000ff>operator</font>()() {
<font color=#0000ff>return</font> <font color=#0000ff>new</font> Bicycle;
}
};
#endif <font color=#009900>// BICYCLE_H ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>operator<<</B> for
<B>ostream</B> and <B>Bicycle</B> moves through and calls the
<B>operator<<</B> for each <B>BicyclePart</B>, and that prints out the
class name of the part so you can see what a <B>Bicycle</B> contains. The
<B>BicyclePart::clone( )</B> member function is necessary in the
copy-constructor of <B>Bicycle</B>, since it just has a
<B>vector<BicyclePart*></B> and wouldn’t otherwise know how to copy
the <B>BicyclePart</B>s correctly. The cloning process, of course, will be more
involved when there are data members in a <B>BicyclePart</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>BicyclePart::partcount</B> is used to
keep track of the number of parts created and destroyed (so you can detect
memory leaks). It is incremented every time a new <B>BicyclePart</B> is created
and decremented when one is destroyed; also, when <B>partcount</B> goes to zero
this is reported and if it goes below zero there will be an
<B>assert( )</B> failure.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you want to change <B>BicyclePart</B>s
on a <B>Bicycle</B>, you just call <B>Bicycle::bikeParts( )</B> to get the
<B>vector<BicyclePart*></B> which you can then modify. But whenever you
remove a part from a <B>Bicycle</B>, you must call <B>delete</B> for that
pointer, otherwise it won’t get cleaned up.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s the
implementation:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:Bicycle.cpp {O}</font>
<font color=#009900>// Bicycle implementation</font>
#include <font color=#004488>"Bicycle.h"</font>
#include <map>
#include <algorithm>
#include <cassert>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#009900>// Static member definitions:</font>
LeakChecker BicyclePart::lc;
<font color=#0000ff>int</font> Bicycle::counter = 0;
Bicycle::Bicycle() : id(counter++) {
BicyclePart *bp[] = {
<font color=#0000ff>new</font> Part<Frame>,
<font color=#0000ff>new</font> Part<Wheel>, <font color=#0000ff>new</font> Part<Wheel>,
<font color=#0000ff>new</font> Part<Seat>, <font color=#0000ff>new</font> Part<HandleBar>,
<font color=#0000ff>new</font> Part<Sprocket>, <font color=#0000ff>new</font> Part<Deraileur>,
};
<font color=#0000ff>const</font> <font color=#0000ff>int</font> bplen = <font color=#0000ff>sizeof</font> bp / <font color=#0000ff>sizeof</font> *bp;
parts = VBP(bp, bp + bplen);
}
Bicycle::Bicycle(<font color=#0000ff>const</font> Bicycle& old)
: parts(old.parts.begin(), old.parts.end()) {
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < parts.size(); i++)
parts[i] = parts[i]->clone();
}
Bicycle& Bicycle::<font color=#0000ff>operator</font>=(<font color=#0000ff>const</font> Bicycle& old) {
purge(); <font color=#009900>// Remove old lvalues</font>
parts.resize(old.parts.size());
copy(old.parts.begin(),
old.parts.end(), parts.begin());
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < parts.size(); i++)
parts[i] = parts[i]->clone();
<font color=#0000ff>return</font> *<font color=#0000ff>this</font>;
}
<font color=#0000ff>void</font> Bicycle::purge() {
<font color=#0000ff>for</font>(VBP::iterator it = parts.begin();
it != parts.end(); it++) {
<font color=#0000ff>delete</font> *it;
*it = 0; <font color=#009900>// Prevent multiple deletes</font>
}
}
ostream& <font color=#0000ff>operator</font><<(ostream& os, Bicycle* b) {
copy(b->parts.begin(), b->parts.end(),
ostream_iterator<BicyclePart*>(os, <font color=#004488>"\n"</font>));
os << <font color=#004488>"--------"</font> << endl;
<font color=#0000ff>return</font> os;
}
<font color=#0000ff>void</font> Bicycle::print(vector<Bicycle*>& vb,
ostream& os) {
copy(vb.begin(), vb.end(),
ostream_iterator<Bicycle*>(os, <font color=#004488>"\n"</font>));
cout << <font color=#004488>"--------"</font> << endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s a test:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:BikeTest.cpp</font>
<font color=#009900>//{L} Bicycle ../TestSuite/Test</font>
#include <font color=#004488>"Bicycle.h"</font>
#include <algorithm>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>int</font> main() {
vector<Bicycle*> bikes;
BicycleGenerator bg;
generate_n(back_inserter(bikes), 12, bg);
Bicycle::print(bikes);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
<A NAME="_Toc519042123"></A><BR>Factories: encapsulating object creation</H2></FONT>
<A NAME="Heading333"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When you discover that you need to add
new types to a system, the most sensible first step to take is to use
polymorphism to create a common interface to those new types. This separates the
rest of the code in your system from the knowledge of the specific types that
you are adding. New types may be added without disturbing existing code ... or
so it seems. At first it would appear that the only place you need to change the
code in such a design is the place where you inherit a new type, but this is not
quite true. You must still create an object of your new type, and at the point
of creation you must specify the exact constructor to use. Thus, if the code
that creates objects is distributed throughout your application, you have the
same problem when adding new types – you must still chase down all the
points of your code where type matters. It happens to be the <I>creation</I> of
the type that matters in this case rather than the <I>use</I> of the type (which
is taken care of by polymorphism), but the effect is the same: adding a new type
can cause problems.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The solution is to force the creation of
objects to occur through a common <I>factory</I> rather than to allow the
creational code to be spread throughout your system. If all the code in your
program must go through this factory whenever it needs to create one of your
objects, then all you must do when you add a new object is to modify the
factory. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Since every object-oriented program
creates objects, and since it’s very likely you will extend your program
by adding new types, I suspect that factories may be the most universally useful
kinds of design patterns.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As an example, let’s revisit the
<B>Shape</B> system. One approach is to make the factory a <B>static</B> method
of the base class:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:ShapeFactory1.cpp</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <font color=#004488>"..</font><font color=#004488>/purge.h"</font>
#include <iostream>
#include <string>
#include <exception>
#include <vector>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> Shape {
<font color=#0000ff>public</font>:
<font color=#0000ff>virtual</font> <font color=#0000ff>void</font> draw() = 0;
<font color=#0000ff>virtual</font> <font color=#0000ff>void</font> erase() = 0;
<font color=#0000ff>virtual</font> ~Shape() {}
<font color=#0000ff>class</font> BadShapeCreation : <font color=#0000ff>public</font> exception {
string reason;
<font color=#0000ff>public</font>:
BadShapeCreation(string type) {
reason = <font color=#004488>"Cannot create type "</font> + type;
}
~BadShapeCreation() <font color=#0000ff>throw</font>() {}
<font color=#0000ff>const</font> <font color=#0000ff>char</font> *what() <font color=#0000ff>const</font> <font color=#0000ff>throw</font>() {
<font color=#0000ff>return</font> reason.c_str();
}
};
<font color=#0000ff>static</font> Shape* factory(string type)
<font color=#0000ff>throw</font>(BadShapeCreation);
};
<font color=#0000ff>class</font> Circle : <font color=#0000ff>public</font> Shape {
Circle() {} <font color=#009900>// Private constructor</font>
<font color=#0000ff>friend</font> <font color=#0000ff>class</font> Shape;
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font> draw() { cout << <font color=#004488>"Circle::draw\n"</font>; }
<font color=#0000ff>void</font> erase() { cout << <font color=#004488>"Circle::erase\n"</font>; }
~Circle() { cout << <font color=#004488>"Circle::~Circle\n"</font>; }
};
<font color=#0000ff>class</font> Square : <font color=#0000ff>public</font> Shape {
Square() {}
<font color=#0000ff>friend</font> <font color=#0000ff>class</font> Shape;
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font> draw() { cout << <font color=#004488>"Square::draw\n"</font>; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -