📄 index.html
字号:
}
}</pre>
</blockquote>
</li>
</ul>
</font>
<hr><h2><font color="#009999">26.3 The ADAPTER Pattern</font></h2>
<font size="+1">
<ul>
<li>When you want to use an existing class, but its i/f doesn't match the
one you need</li>
<li>Consider converting a string containing numerics (<tt>"235"</tt>) to
an integer:
<ul>
<li><tt>string</tt> can't</li>
<li>If digits were stored in a stream, great</li>
<li>Hence, the <tt>istringstream</tt> class (chptr 12):
<blockquote><tt>
string s = "235";<br>
istringstream istr(s);<br>
int n;<br>
s >> n;
<font color="#0000cc">// Now n is the integer 235</font>
</tt></blockquote>
</li>
</ul>
</li>
</ul>
</font>
<hr><h2><font color="#009999">26.3 The ADAPTER Pattern (cont.)</font></h2>
<font size="+1">
<ul>
<li>The <tt>>></tt> operator repeatedly calls <tt>get()</tt>, then
assembles the integer</li>
<li><tt>istringstream</tt> defines a <tt>get</tt> function to obtain the
characters from a string, using <tt>string::operator[]</tt>
<li>Example of the ADAPTER pattern</li>
</ul>
</font>
<hr><h2><font color="#009999">Pattern ADAPTER</font></h2>
<font size="+1">
<hr color="#00ffff" size="6">
<h3><font color="#009999">Context</font></h3>
<ol>
<li>You want to use an existing class (<i>adaptee</i>) w/out modifying it</li>
<li>The context requires conformance to a <i>target</i> i/f, different from
the adaptee's</li>
<li>Target i/f and adaptee i/f are conceptually related</li>
</ol>
</font>
<hr><h2><font color="#009999">Pattern ADAPTER (cont.)</font></h2>
<font size="+1">
<hr color="#00ffff" size="6">
<h3><font color="#009999">Solution</font></h3>
<ol>
<li>Define an <i>adapter</i> class that implements the target i/f</li>
<li>Adapter class translates target functions to adaptee functions</li>
<li>The client wraps the adaptee into an adapter class object</li>
</ol>
</font>
<hr><h2><font color="#009999">Pattern ADAPTER (cont.)</font></h2>
<font size="+1">
<hr color="#00ffff" size="6">
<h3><font color="#009999">Solution</font></h3>
<script><!--
image( "un04.png" )
//--></script>
</font>
<hr><h2><font color="#009999">26.3 The ADAPTER Pattern (cont.)</font></h2>
<font size="+1">
<ul>
<table border='1' cellpadding='4'>
<tr bgcolor="#00ffff">
<th width='50%'>Name in Design Pattern</th>
<th width='50%'>Actual Name (String Streams)</th>
</tr>
<tr>
<td align='center'><tt>Adaptee</tt></td>
<td align='center'><tt>string</tt></td>
</tr>
<tr>
<td align='center'><tt>Target</tt></td>
<td align='center'><tt>istream</tt></td>
</tr>
<tr>
<td align='center'><tt>Adapter</tt></td>
<td align='center'><tt>istringstream</tt></td>
</tr>
<tr>
<td align='center'><tt>Client</tt></td>
<td align='center'>Code that wants to use <tt>operator>></tt> to
read string</td>
</tr>
<tr>
<td align='center'><tt>target_function()</tt></td>
<td align='center'><tt>get()</tt></td>
</tr>
<tr>
<td align='center'><tt>adaptee_function</tt></td>
<td align='center'><tt>operator[]</tt></td>
</tr>
</table>
</ul>
</font>
<hr><h2><font color="#009999">26.3 The ADAPTER Pattern (cont.)</font></h2>
<font size="+1">
<h3>Other ADAPTERS:</h3>
<ul>
<li><tt>ostream_iterator</tt> wraps a stream with an iterator i/f:
<blockquote><tt>
copy( source.begin(), source.end(),
<nobr>ostream_iterator<string></nobr>( cout, "\n" ));
</tt></blockquote>
<ul>
<li>Overload the <tt>*</tt> and <tt>=</tt> operators</li>
<li><tt>operator++</tt> overloaded to do nothing</li>
</ul>
</li>
</ul>
</font>
<hr><h2><font color="#009999">26.3 The ADAPTER Pattern (cont.)</font></h2>
<font size="+1">
<ul>
<li>Can be used to read from a stream:
<blockquote><tt>
copy( <nobr>istream_iterator<string>(cin),</nobr>
<nobr>istream_iterator<string>(),<nobr> target.begin() );
</tt></blockquote>
<ul>
<li>Default c'tor, <tt>istream_iterator<string>()</tt>, creates
end-of-stream sentinel</li>
<li>Overload the <tt>*</tt> and <tt>!=</tt> operators</li>
</ul>
</li>
</ul>
</font>
<hr><h2><font color="#009999">26.3 The ADAPTER Pattern (cont.)</font></h2>
<font size="+1">
<ul>
<table border='1' cellpadding='4'>
<tr bgcolor="#00ffff">
<th width='50%'>Name in Design Pattern</th>
<th width='50%'>Actual Name (String Streams)</th>
</tr>
<tr>
<td align='center'><tt>Adaptee</tt></td>
<td align='center'><tt>istream, ostream</tt></td>
</tr>
<tr>
<td align='center'><tt>Target</tt></td>
<td align='center'><tt>iterator</tt></td>
</tr>
<tr>
<td align='center'><tt>Adapter</tt></td>
<td align='center'><tt>istream_iterator, ostream_iterator</tt></td>
</tr>
<tr>
<td align='center'><tt>Client</tt></td>
<td align='center'>Code that wants to use a stream</td>
</tr>
<tr>
<td align='center'><tt>target_function()</tt></td>
<td align='center'><tt><<, >>, fail()</tt></td>
</tr>
<tr>
<td align='center'><tt>adaptee_function</tt></td>
<td align='center'>The <tt>*, =, +, !=</tt> operators</td>
</tr>
</table>
</ul>
</font>
<hr><h2><font color="#009999">26.4 The TEMPLATE METHOD Pattern</font></h2>
<font size="+1">
<ul>
<li>Pattern where an algorithm is mostly implemented in a base class, even
when some details are unknown</li>
<li>Details supplied in virtual methods in derived classes</li>
<li>The base class template method tells how to fit in the details</li>
</ul>
</font>
<hr><h2><font color="#009999">26.4 The TEMPLATE METHOD Pattern (cont.)
</font></h2>
<font size="+1">
<p>Example - stream buffers</p>
<ul>
<li>Each (buffered) stream has an associated stream</li>
<li>Characters sent to buffer</li>
<li>When buffer is full, contents are written to its target (file, screen,
etc.)</li>
<li>More efficient</li>
<li><tt>ofstream</tt> and <tt>ostringstream</tt> differ only by the
attached buffers:
<ul>
<li><tt>ofstream</tt> has a <tt>filebuf</tt> object</li>
<li><tt>ostringstream</tt> has a <tt>stringbuf</tt> object</li>
</ul>
</li>
</ul>
</font>
<hr><h2><font color="#009999">26.4 The TEMPLATE METHOD Pattern (cont.)
</font></h2>
<font size="+1">
<p>Example - stream buffers (cont.)</p>
<ul>
<li>Consider an output operation:
<blockquote><tt>
cout << "Hello, World!\n";
</tt></blockquote>
</li>
<li>The appropriate <tt>operator<<</tt> is invoked:</li>
<ul>
<li>Converts each value into a sequence of characters</li>
<li>Inserts each character into a stream buffer</li>
</ul>
</li>
</ul>
</font>
<hr><h2><font color="#009999">26.4 The TEMPLATE METHOD Pattern (cont.)
</font></h2>
<font size="+1">
<p>Example - stream buffers (cont.)</p>
<ul>
<li>One possible implementation:
<blockquote>
<pre>ostream& ostream::operator<<(const char s[])
{
int i = 0;
while (s[i] != '\0')
{
rdbuf()->sputc(s[i]); <font color="#0000cc">// returns a ptr to the buffer</font>
i++;
}
return *this;
}</pre>
</blockquote>
</li>
</ul>
</font>
<hr><h2><font color="#009999">26.4 The TEMPLATE METHOD Pattern (cont.)
</font></h2>
<font size="+1">
<p>Example - stream buffers (cont.)</p>
<ul>
<li>Insert a character into the buffer:
<blockquote>
<pre>int streambuf::sputc(char c)
{
if (buffer full )
return overflow(c);
else
{
add c to the buffer
return c;
}
}</pre>
</blockquote>
</li>
</ul>
</font>
<hr><h2><font color="#009999">26.4 The TEMPLATE METHOD Pattern (cont.)
</font></h2>
<font size="+1">
<p>Example - stream buffers (cont.)</p>
<ul>
<li><tt>overflow</tt> writes the buffer content (and <tt>c</tt>) to its
destination</li>
<li><tt>overflow</tt> is a virtual method</li>
<li>Has a dummy implementation in <tt>streambuf</tt>, returns <tt>EOF</tt>
</li>
<li>Derived classes redefine <tt>overflow</tt></li>
<li><tt>streambuf::sputc</tt> is <b>not</b> redefined</li>
</ul>
</font>
<hr><h2><font color="#009999">26.4 The TEMPLATE METHOD Pattern (cont.)
</font></h2>
<font size="+1">
<ul>
<li><tt>sputc</tt> is an example of the TEMPLATE METHOD Pattern</li>
<ul>
<li>(Nothing to do w/C++ templates)</li>
</ul>
<li>Base class defines an algorithm that calls
<i>primitive operations</i></li>
<li>Algorithm depends on derived class defining an appropriate operation</li>
<li>The template method combines primitive operations into a larger
algorithm</li>
</ul>
</font>
<hr><h2><font color="#009999">Pattern TEMPLATE METHOD</font></h2>
<font size="+1">
<hr color="#00ffff" size="6">
<h3><font color="#009999">Context</font></h3>
<ol>
<li>An algorithm is applicable for multiple types</li>
<li>Algorithm can be broken into <i>primitive operations</i></li>
<li>The order of execution of the primitives doesn't depend on the type</li>
</ol>
</font>
<hr><h2><font color="#009999">Pattern TEMPLATE METHOD</font></h2>
<font size="+1">
<hr color="#00ffff" size="6">
<h3><font color="#009999">Solution</font></h3>
<table cellpadding='5'>
<tr>
<td valign='top'><font size='+1'>
<ol>
<li>Define the algorithm in the base class</li>
<li>The algorithm calls the primitive operations in order</li>
<li>Define the primitive operations as virtual functions in base class,
with appropriate default behavior, or leave undefined</li>
<li>Each derived class defines the primitives, but not the algorithm
</li>
</ol>
</font>
</td>
<td>
<script><!--
image( "un05.png" )
//--></script>
</td>
</tr>
</table>
</font>
<hr><h2><font color="#009999">26.4 The TEMPLATE METHOD Pattern (cont.)
</font></h2>
<font size="+1">
<ul>
<table border='1' cellpadding='4'>
<tr bgcolor="#00ffff">
<th width='50%'>Name in Design Pattern</th>
<th width='50%'>Actual Name (Stream Buffers)</th>
</tr>
<tr>
<td align='center'><tt>AbstractClass</tt></td>
<td align='center'><tt>streambuf</tt></td>
</tr>
<tr>
<td align='center'><tt>ConcreteClass</tt></td>
<td align='center'><tt>filebuf, stringbuf</tt></td>
</tr>
<tr>
<td align='center'><tt>template_method()</tt></td>
<td align='center'><tt>sputc</tt></td>
</tr>
<tr>
<td align='center'><tt>primitive_op1</tt></td>
<td align='center'><tt>overflow</tt></td>
</tr>
</table>
</ul>
</font>
<hr><h2><font color="#009999">26.5 Function Objects and the STRATEGY Pattern
</font></h2>
<h2><font color="#009999">26.5.1 Function Objects</font></h2>
<font size="+1">
<ul>
<li>STRATEGY pattern shows how to supply a variety of algorithms to a
computation</li>
<li>Motivation: the STL <tt>sort</tt></li>
<li>E.g., sorting a vector of strings:
<blockquote><tt>
<nobr>vector<string></nobr> names;<br>
. . .<br>
sort(<nobr>names.begin(),</nobr> <nobr>names.end()</nobr>);
</tt></blockquote>
</li>
</ul>
</font>
<hr><h2><font color="#009999">26.5.1 Function Objects (cont.)</font></h2>
<font size="+1">
<ul>
<li><tt>sort</tt> works on any type that has <tt>operator<</tt></li>
<li>Defined on strings, uses dictionary order</li>
<li>Consider sorting Employees:
<blockquote><tt>
<nobr>vector<Employee></nobr> staff;<br>
sort(<nobr>staff.begin(),</nobr> <nobr>staff.end()</nobr>);
</tt></blockquote>
</li>
<li>To sort by name, supply:
<blockquote>
<pre>bool operator<(const Employee& a, const Employee& b)
{
return a.get_name() < b.get_name();
}</pre>
</blockquote>
</li>
</ul>
</font>
<hr><h2><font color="#009999">26.5.1 Function Objects (cont.)</font></h2>
<font size="+1">
<ul>
<li>Sort by salary?</li>
<li>Redefine <tt>operator<</tt> for each sort order?</li>
<li>Sol'n: don't use the default <tt>operator<</tt>
<blockquote><tt>
SalaryComparator comp;<br>
sort(<nobr>staff.begin(),</nobr> <nobr>staff.end(),</nobr> comp);
</tt></blockquote>
</li>
<li>(more concisely):
<blockquote><tt>
sort(<nobr>staff.begin(),</nobr> <nobr>staff.end(),</nobr>
<nobr>SalaryComparator()</nobr>);
</tt></blockquote>
</li>
<li>Template function ptrs are messy, so we use a function object</li>
</ul>
</font>
<hr><h2><font color="#009999">26.5.1 Function Objects (cont.)</font></h2>
<font size="+1">
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -