📄 chap11.htm
字号:
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The implementation <I>must not be
inlined</I>, because that would mean that the whole function, including the
static object definition within, could be duplicated in any translation unit
where it’s included, and you’d end up with multiple copies of the
static object. This would most certainly foil the attempts to control the order
of initialization (but potentially in a very subtle and hard-to-detect fashion).
So the implementation must be separate:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:LogFile.cpp {O}</font>
#include <font color=#004488>"LogFile.h"</font>
std::ofstream& logfile() {
<font color=#0000ff>static</font> std::ofstream log(<font color=#004488>"Logfile.log"</font>);
<font color=#0000ff>return</font> log;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now the <B>log</B> object will not be
initialized until the first time <B>logfile( )</B> is called. So if you use
the function in one file:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:UseLog1.h</font>
#ifndef USELOG1_H
#define USELOG1_H
<font color=#0000ff>void</font> f();
#endif <font color=#009900>// USELOG1_H ///:~</font>
<font color=#009900>//: C11:UseLog1.cpp {O}</font>
#include <font color=#004488>"UseLog1.h"</font>
#include <font color=#004488>"LogFile.h"</font>
<font color=#0000ff>void</font> f() {
logfile() << __FILE__ << std::endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">And again in another
file:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:UseLog2.cpp</font>
<font color=#009900>//{L} UseLog1 LogFile ../TestSuite/Test</font>
#include <font color=#004488>"UseLog1.h"</font>
#include <font color=#004488>"LogFile.h"</font>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>void</font> g() {
logfile() << __FILE__ << endl;
}
<font color=#0000ff>int</font> main() {
f();
g();
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Then the <B>log </B>object doesn’t
get created until the first call to <B>f( )</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can easily combine the creation of
the static object inside a member function with the singleton class.
<B>SingletonPattern.cpp</B> can be modified to use this
approach:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:SingletonPattern2.cpp</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> Singleton {
<font color=#0000ff>int</font> i;
Singleton(<font color=#0000ff>int</font> x) : i(x) { }
<font color=#0000ff>void</font> <font color=#0000ff>operator</font>=(Singleton&);
Singleton(<font color=#0000ff>const</font> Singleton&);
<font color=#0000ff>public</font>:
<font color=#0000ff>static</font> Singleton& getHandle() {
<font color=#0000ff>static</font> Singleton s(47);
<font color=#0000ff>return</font> s;
}
<font color=#0000ff>int</font> getValue() { <font color=#0000ff>return</font> i; }
<font color=#0000ff>void</font> setValue(<font color=#0000ff>int</font> x) { i = x; }
};
<font color=#0000ff>int</font> main() {
Singleton& s = Singleton::getHandle();
cout << s.getValue() << endl;
Singleton& s2 = Singleton::getHandle();
s2.setValue(9);
cout << s.getValue() << endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">An especially interesting case is if two
of these singletons depend on each other, like this:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:FunctionStaticSingleton.cpp</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#0000ff>class</font> Singleton1 {
Singleton1() {}
<font color=#0000ff>public</font>:
<font color=#0000ff>static</font> Singleton1& ref() {
<font color=#0000ff>static</font> Singleton1 single;
<font color=#0000ff>return</font> single;
}
};
<font color=#0000ff>class</font> Singleton2 {
Singleton1& s1;
Singleton2(Singleton1& s) : s1(s) {}
<font color=#0000ff>public</font>:
<font color=#0000ff>static</font> Singleton2& ref() {
<font color=#0000ff>static</font> Singleton2 single(Singleton1::ref());
<font color=#0000ff>return</font> single;
}
Singleton1& f() { <font color=#0000ff>return</font> s1; }
};
<font color=#0000ff>int</font> main() {
Singleton1& s1 = Singleton2::ref().f();
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When <B>Singleton2::ref( )</B> is
called, it causes its sole <B>Singleton2</B> object to be created. In the
process of this creation, <B>Singleton1::ref( )</B> is called, and that
causes the sole <B>Singleton1</B> object to be created. Because this technique
doesn’t rely on the order of linking or loading, the programmer has much
better control over initialization, leading to less problems.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You’ll see further examples of the
singleton pattern in the rest of this
chapter.</FONT><A NAME="_Toc408018796"></A><A NAME="_Toc519042119"></A><BR></P></DIV>
<A NAME="Heading329"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Classifying patterns</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <I>Design Patterns</I> book discusses
23 different patterns, classified under three purposes (all of which revolve
around the particular aspect that can vary). The three purposes
are:</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="Index657"></A><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana"> <A NAME="Index658"></A></FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>Creational</B>:
how an object can be created. This often involves isolating the details of
object creation so your code isn’t dependent on what types of objects
there are and thus doesn’t have to be changed when you add a new type of
object. The aforementioned <I>Singleton</I> is classified as a creational
pattern, and later in this chapter you’ll see examples of <I>Factory
Method</I> and <I>Prototype</I>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="Index659"></A><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana"> <A NAME="Index660"></A></FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>Structural</B>:
designing objects to satisfy particular project constraints. These work with the
way objects are connected with other objects to ensure that changes in the
system don’t require changes to those connections.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="Index661"></A><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana"> <A NAME="Index662"></A></FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>Behavioral</B>:
objects that handle particular types of actions within a program. These
encapsulate processes that you want to perform, such as interpreting a language,
fulfilling a request, moving through a sequence (as in an iterator), or
implementing an algorithm. This chapter contains examples of the <I>Observer</I>
and the <I>Visitor</I> patterns.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <I>Design Patterns</I> book has a
section on each of its 23 patterns along with one or more examples for each,
typically in C++ but sometimes in Smalltalk. This book will not repeat all the
details of the patterns shown in <I>Design Patterns</I> since that book stands
on its own and should be studied separately. The catalog and examples provided
here are intended to rapidly give you a grasp of the patterns, so you can get a
decent feel for what patterns are about and why they are so
important.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">[[ Describe different form of
categorization, based on what you want to accomplish rather than the way the
patterns look. More categories, but should result in easier-to-understand,
faster selection
]]]</FONT><A NAME="_Toc375545413"></A><A NAME="_Toc408018797"></A><A NAME="_Toc519042120"></A><BR></P></DIV>
<A NAME="Heading330"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Features, idioms, patterns</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">How things have gotten confused;
conflicting pattern descriptions, naïve “patterns,” patterns
are not trivial nor are they represented by features that are built into the
language, nor are they things that you do almost all the time. Constructors and
destructors, for example, could be called the “guaranteed initialization
and cleanup design pattern.” This is an important and essential idea, but
it’s built into the language.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Another example comes from various forms
of aggregation. Aggregation is a completely fundamental principle in
object-oriented programming: you make objects out of other objects [[ make
reference to basic tenets of OO ]]. Yet sometimes this idea is classified as a
pattern, which tends to confuse the issue. This is unfortunate because it
pollutes the idea of the design pattern and suggest that anything that surprises
you the first time you see it should be a design pattern.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Another misguided example is found in the
Java language; the designers of the “JavaBeans” specification
decided to refer to a simple naming convention as a design pattern (you say
<B>getInfo( )</B> for a member function that returns an <B>Info</B>
property and <B>setInfo( )</B> for one that changes the internal
<B>Info</B> property; the use of the “get” and “set”
strings is what they decided constituted calling it a design
pattern).</FONT><A NAME="_Toc519042121"></A><BR></P></DIV>
<A NAME="Heading331"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Basic complexity hiding</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You’ll often find that messy code
can be cleaned up by putting it inside a class. This is more than fastidiousness
– if nothing else, it aids readability and therefore maintainability, and
it can often lead to reusability.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Simple Veneer (façade, Adapter
(existing system), Bridge (designed in), </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Hiding types (polymorphism, iterators,
proxy)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Hiding connections
(mediator,)</FONT><A NAME="_Toc519042122"></A><BR></P></DIV>
<A NAME="Heading332"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Dynamic aggregation</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">[[ This may actually be the
“builder” design pattern in some form ]]</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The examples we’ve seen so far are
illustrative, but fairly simple. It’s useful to see an example that has
more complexity so you can see that the STL will work in all
situations.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">[[ Add a factory method that takes a
vector of string]]</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The class that will be created as the
example will be reasonably complex: it’s a bicycle which can have a choice
of parts. In addition, you can change the parts during the lifetime of a
<B>Bicycle</B> object; this includes the ability to add new parts or to upgrade
from standard-quality parts to “fancy” parts. The <B>BicyclePart</B>
class is a base class with many different types, and the <B>Bicycle</B> class
contains a <B>vector<BicyclePart*></B> to hold the various combination of
parts that may be attached to a <B>Bicycle</B>:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C11:Bicycle.h</font>
<font color=#009900>// Complex class involving dynamic aggregation</font>
#ifndef BICYCLE_H
#define BICYCLE_H
#include <vector>
#include <string>
#include <iostream>
#include <typeinfo>
<font color=#0000ff>class</font> LeakChecker {
<font color=#0000ff>int</font> count;
<font color=#0000ff>public</font>:
LeakChecker() : count(0) {}
<font color=#0000ff>void</font> print() {
std::cout << count << std::endl;
}
~LeakChecker() { print(); }
<font color=#0000ff>void</font> <font color=#0000ff>operator</font>++(<font color=#0000ff>int</font>) { count++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -