﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-michael-随笔分类-设计模式</title><link>http://www.cppblog.com/michaelgao/category/8288.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 07 Jan 2009 01:25:19 GMT</lastBuildDate><pubDate>Wed, 07 Jan 2009 01:25:19 GMT</pubDate><ttl>60</ttl><item><title>C++完美实现Singleton模式</title><link>http://www.cppblog.com/michaelgao/archive/2009/01/06/71345.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Tue, 06 Jan 2009 08:06:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2009/01/06/71345.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/71345.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2009/01/06/71345.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/71345.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/71345.html</trackback:ping><description><![CDATA[http://www.cppblog.com/dyj057/archive/2005/09/20/346.html<br><br>大家都知道，在用C++来实现Singleton模式的时候通常把构造函数声明为私有的或者保护的。同时声明一个公有的静态的伪构造函数，通过它来调用真正的构造函数。在实现这个伪构造函数的时候通常有两种方式： &nbsp; <br> &nbsp; class &nbsp; Singleton; &nbsp; <br> &nbsp;  &nbsp; <br> &nbsp; static &nbsp; Singleton&amp; &nbsp; Singleton:;fakeSingleton() &nbsp; <br> &nbsp; { &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; static &nbsp; Singleton &nbsp; s; &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; return &nbsp; s; &nbsp; <br> &nbsp; } &nbsp; <br> &nbsp; 第二种方式: &nbsp; <br> &nbsp; class &nbsp; Singleton{ &nbsp; <br> &nbsp; public: &nbsp; <br> &nbsp; static &nbsp; Singleton* &nbsp; fakeSingleton(); &nbsp; <br> &nbsp; ... &nbsp; <br> &nbsp; private: &nbsp; <br> &nbsp; Singleton(); &nbsp; <br> &nbsp; static &nbsp; Singleton &nbsp; * &nbsp; _instance; &nbsp; <br> &nbsp; } &nbsp; <br> &nbsp; Singleton* &nbsp; Singleton::fakesinketon() &nbsp; <br> &nbsp; { &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp; if( &nbsp; _instance==NULL) &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; _instance=new &nbsp; Singleton(); &nbsp; <br> &nbsp;  &nbsp;  &nbsp;  &nbsp;  &nbsp; return &nbsp; _instance; &nbsp; <br> &nbsp; } &nbsp; <br> &nbsp; 对于这两种方式我觉得第一种更好一些，理由是，如果有两个以上的线程同时访问伪构造函数的时候有可能同时进入if &nbsp; 控制块，这样就有可能产生两个实例！！因此必须采用特殊的保护机制来控制同步。而第一种方式不存在这样的问题。 &nbsp; <br> &nbsp;  &nbsp; <br> &nbsp; 请高手指点！我不明白的是，为什么书上的例子还较多的采用第二种方法？莫非它有自己的优势？？ &nbsp; <br> &nbsp;  &nbsp;
<br><img src ="http://www.cppblog.com/michaelgao/aggbug/71345.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2009-01-06 16:06 <a href="http://www.cppblog.com/michaelgao/archive/2009/01/06/71345.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>The "Double-Checked Locking is Broken" Declaration  sigleleton 模式</title><link>http://www.cppblog.com/michaelgao/archive/2008/10/23/64806.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Thu, 23 Oct 2008 06:25:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/10/23/64806.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/64806.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/10/23/64806.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/64806.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/64806.html</trackback:ping><description><![CDATA[<h1 align="center">
The "Double-Checked Locking is Broken" Declaration
</h1>
<p align="center"><em> Signed by</em> :
<a href="http://www.research.ibm.com/people/d/dfb">David Bacon</a> (IBM Research)
Joshua Bloch (Javasoft),
<a href="http://www.cs.ucsb.edu/%7Ebogda/">Jeff Bogda</a>,
Cliff Click (Hotspot JVM project),
<a href="http://www.webcom.com/%7Ehaahr/">Paul Haahr</a>,
<a href="http://www.cs.oswego.edu/%7Edl">Doug Lea</a>,
<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#116;&#111;&#109;&#64;&#103;&#111;&#50;&#110;&#101;&#116;&#46;&#99;&#111;&#109;">Tom May</a>,
<a href="http://www.csg.lcs.mit.edu/%7Eearwig/">Jan-Willem Maessen</a>,
<a href="http://www.cs.umd.edu/%7Ejmanson">Jeremy Manson</a>,
<a href="http://www.jguru.com/johnm">John D. Mitchell (jGuru)</a>
Kelvin Nilsen,
<a href="http://www.cs.umd.edu/%7Epugh">Bill Pugh</a>,
<a href="http://www.cs.washington.edu/homes/egs/">Emin Gun Sirer</a>
</p>
<p>
Double-Checked Locking is widely cited and used
as an efficient method for implementing
lazy initialization
in a multithreaded environment.
</p>
<p>Unfortunately, it
will not work reliably in a platform independent way
when implemented in Java, without additional synchronization.
When implemented in other languages, such as C++, it depends on
the memory model of the processor, the reorderings performed by
the compiler and the interaction between the compiler and the synchronization
library. Since none of these are specified in a language such as C++,
little can be said about the situations in which it will work. Explicit
memory barriers can be used to make it work in C++, but these barriers are
not available in Java.
</p>
<p>
To first explain the desired behavior, consider the following code:
</p>
<p>
<table border="2">
    <tbody>
        <tr>
            <td>
            <pre>// Single threaded version<br>class Foo { <br>  private Helper helper = null;<br>  public Helper getHelper() {<br>    if (helper == null) <br>        helper = new Helper();<br>    return helper;<br>    }<br>  // other functions and members...<br>  }<br></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>
If this code was used in a multithreaded context,
many things could go wrong. Most obviously, two or more
<tt>Helper</tt> objects could be allocated. (We'll bring up other problems
later).
The fix to this is simply to synchronize the
<tt>getHelper()</tt> method:
</p>
<p>
<table border="2">
    <tbody>
        <tr>
            <td>
            <pre>// Correct multithreaded version<br>class Foo { <br>  private Helper helper = null;<br>  public synchronized Helper getHelper() {<br>    if (helper == null) <br>        helper = new Helper();<br>    return helper;<br>    }<br>  // other functions and members...<br>  }<br></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>
The code above performs synchronization every time
<tt>getHelper()</tt>
is called.
The double-checked locking idiom tries to avoid synchronization
after the helper is allocated:
</p>
<p>
<table border="2">
    <tbody>
        <tr>
            <td>
            <pre>// Broken multithreaded version<br>// "Double-Checked Locking" idiom<br>class Foo { <br>  private Helper helper = null;<br>  public Helper getHelper() {<br>    if (helper == null) <br>      synchronized(this) {<br>        if (helper == null) <br>          helper = new Helper();<br>      }    <br>    return helper;<br>    }<br>  // other functions and members...<br>  }<br></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>
Unfortunately, that code just
does not work in the presence of either optimizing compilers
or shared memory multiprocessors.
</p>
<h2>It doesn't work</h2>
<p>There are lots of reasons it doesn't work. The first couple of
reasons we'll describe are more obvious. After understanding those, you may be tempted
to try to devise a way to "fix" the double-checked locking idiom. Your fixes will not
work: there are more subtle reasons why your fix won't work. Understand those
reasons, come up with a better fix, and it still won't work, because there are even
more subtle reasons.
</p>
<p>Lots of very smart people have spent lots of time looking at this.
There is <em> no way</em>  to make it work without requiring each thread that
accesses the helper object to perform synchronization.
</p>
<h3>The first reason it doesn't work</h3>
<p>The most obvious reason it doesn't work it
that the writes that initialize the
<tt>Helper</tt> object
and the write to the
<tt>helper</tt> field can be done or perceived
out of order. Thus, a thread which invokes getHelper() could see a non-null
reference to a helper object, but see the default values for fields of the
helper object, rather than the values set in the constructor.
</p>
<p>
If the compiler inlines the call to the constructor, then the writes
that initialize the object and the write to the
<tt>helper</tt> field
can be freely reordered if the compiler can prove that the constructor
cannot throw an exception or perform synchronization.
</p>
<p>Even if the compiler does not reorder those writes, on a multiprocessor
the processor or the memory system may reorder those writes,
as perceived by
a thread running on another
processor.
</p>
<p>Doug Lea has written
a <a href="http://gee.cs.oswego.edu/dl/cpj/jmm.html">more
detailed description of compiler-based reorderings</a>.
</p>
<h4>A test case showing that it doesn't work</h4>
<p>Paul Jakubik found an example of a use of double-checked locking
that did not work correctly. <a href="http://www.cs.umd.edu/%7Epugh/java/memoryModel/DoubleCheckTest.java">A slightly cleaned up version
of that code is available here</a>.
</p>
<p>When run on a system using the Symantec JIT, it doesn't work.
In particular, the Symantec JIT compiles
</p>
<center>
<pre>singletons[i].reference = new Singleton();</pre>
</center>
<p>to the following (note that the Symantec JIT using
a handle-based object allocation system).
</p>
<pre>0206106A   mov         eax,0F97E78h<br>0206106F   call        01F6B210                  ; allocate space for<br>                                                 ; Singleton, return result in eax<br>02061074   mov         dword ptr [ebp],eax       ; EBP is &amp;singletons[i].reference <br>                                                ; store the unconstructed object here.<br>02061077   mov         ecx,dword ptr [eax]       ; dereference the handle to<br>                                                 ; get the raw pointer<br>02061079   mov         dword ptr [ecx],100h      ; Next 4 lines are<br>0206107F   mov         dword ptr [ecx+4],200h    ; Singleton's inlined constructor<br>02061086   mov         dword ptr [ecx+8],400h<br>0206108D   mov         dword ptr [ecx+0Ch],0F84030h<br></pre>
<p>As you can see, the assignment to
<tt>singletons[i].reference</tt>
is performed before the constructor for Singleton is called.
This is completely legal under the existing Java memory model,
and also legal in C and C++ (since neither of them have a memory model).
</p>
<h4>A fix that doesn't work</h4>
<p>Given the explanation above, a number of people have suggested the
following code:
</p>
<p>
<table border="2">
    <tbody>
        <tr>
            <td>
            <pre>// (Still) Broken multithreaded version<br>// "Double-Checked Locking" idiom<br>class Foo { <br>  private Helper helper = null;<br>  public Helper getHelper() {<br>    if (helper == null) {<br>      Helper h;<br>      synchronized(this) {<br>        h = helper;<br>        if (h == null) <br>            synchronized (this) {<br>              h = new Helper();<br>            } // release inner synchronization lock<br>        helper = h;<br>        } <br>      }    <br>    return helper;<br>    }<br>  // other functions and members...<br>  }<br></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>This code puts construction of the Helper object inside an inner synchronized block.
The intuitive idea here is that there should be a memory
barrier at the point where synchronization is released, and that should
prevent the reordering of the initialization of the
<tt>Helper</tt> object
and the assignment to the field helper.
</p>
<p>Unfortunately, that intuition is absolutely wrong. The rules for
synchronization don't work that way.
The rule for a monitorexit (i.e., releasing synchronization) is that
actions before the monitorexit must be performed before the monitor
is released. However, there is no rule which says that actions after
the monitorexit may not be done before the monitor is released.
It is perfectly reasonable and legal for the compiler to move
the assignment
<tt>helper = h;</tt> inside the synchronized block,
in which case we are back where we were previously. Many processors
offer instructions that perform this kind of one-way memory barrier.
Changing the semantics to require releasing a lock to be a full memory
barrier would have performance penalties.
<!--
<p>Another problem is that the compiler can see that the inner synchronization
block is redundant and eliminate it.
-->
</p>
<h4><a name="readersNeedSync">More fixes that don't work</a></h4>
<p>There is something you can do to force the writer to perform a full
bidirectional
memory barrier. This is gross, inefficient, and is almost guaranteed
not to work once the Java Memory Model is revised. Do not use this. In
the interests of science, <a href="http://www.cs.umd.edu/%7Epugh/java/memoryModel/BidirectionalMemoryBarrier.html">I've put a description of this technique on
a separate page.</a> Do not use it.
</p>
<p><em> However</em> , even with a full memory barrier being performed by
the thread that initializes the helper object, it still doesn't work.
</p>
<p>The problem is that on some systems, the thread
which sees a non-null value for the
<tt>helper</tt> field also needs to perform
memory barriers.
</p>
<p> Why? Because processors have their own locally cached copies of memory.
On some processors, unless the processor performs a cache coherence instruction
(e.g., a memory barrier), reads can be performed out of stale locally cached
copies, even if other processors used memory barriers to force their writes
into global memory.
</p>
<p>I've created <a href="http://www.cs.umd.edu/%7Epugh/java/memoryModel/AlphaReordering.html">a separate web page</a> with a discussion of how this can
actually happen on an Alpha processor.
</p>
<h2>Is it worth the trouble?</h2>
<p>For most applications, the cost of simply making the
<tt>getHelper()</tt>
method synchronized is not high. You should only consider this kind of
detailed optimizations if you know that it is causing a substantial
overhead for an application.
</p>
<p>Very often, more high level cleverness, such as using the builtin
mergesort rather than handling exchange sort (see the SPECJVM DB benchmark)
will have much more impact.
</p>
<h2>Making it work for static singletons</h2>
<p>
If the singleton you are creating is static (i.e., there will only
be one
<tt>Helper</tt> created), as opposed to a property of another
object (e.g., there will be one
<tt>Helper</tt> for
each
<tt>Foo</tt> object,
there is a simple and elegant solution.
</p>
<p>Just define the singleton as a static field in a separate class.
The semantics of Java guarantee that the field will not
be initialized until the field is referenced, and that any thread which
accesses the field will see all of the writes resulting from initializing
that field.
</p>
<p>
<table border="2">
    <tbody>
        <tr>
            <td>
            <pre>class HelperSingleton {<br>  static Helper singleton = new Helper();<br>  }<br></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<h2>It will work for 32-bit primitive values</h2>
<p>Although the double-checked locking idiom cannot be used for references
to objects, it can work for 32-bit primitive values (e.g., int's or float's).
Note that it does not work for long's or double's, since unsynchronized reads/writes
of 64-bit primitives are not guaranteed to be atomic.
</p>
<p>
<table border="2">
    <tbody>
        <tr>
            <td>
            <pre>// Correct Double-Checked Locking for 32-bit primitives<br>class Foo { <br>  private int cachedHashCode = 0;<br>  public int hashCode() {<br>    int h = cachedHashCode;<br>    if (h == 0) <br>    synchronized(this) {<br>      if (cachedHashCode != 0) return cachedHashCode;<br>      h = computeHashCode();<br>      cachedHashCode = h;<br>      }<br>    return h;<br>    }<br>  // other functions and members...<br>  }<br></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>In fact, assuming that the computeHashCode function always
returned the same result and had no side effects (i.e., idempotent),
you could even get rid of all of the synchronization.
</p>
<p>
<table border="2">
    <tbody>
        <tr>
            <td>
            <pre>// Lazy initialization 32-bit primitives<br>// Thread-safe if computeHashCode is idempotent<br>class Foo { <br>  private int cachedHashCode = 0;<br>  public int hashCode() {<br>    int h = cachedHashCode;<br>    if (h == 0) {<br>      h = computeHashCode();<br>      cachedHashCode = h;<br>      }<br>    return h;<br>    }<br>  // other functions and members...<br>  }<br></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<h2><a name="explicitMemoryBarriers">Making it work with explicit memory barriers</a></h2>
<p>It is possible to make the double checked locking pattern work
if you have explicit memory barrier instructions. For example, if
you are programming in C++, you can use the code
from Doug Schmidt et al.'s book:
</p>
<p>
<table border="2">
    <tbody>
        <tr>
            <td>
            <pre>// C++ implementation with explicit memory barriers<br>// Should work on any platform, including DEC Alphas<br>// From "Patterns for Concurrent and Distributed Objects",<br>// by Doug Schmidt<br>template &lt;class TYPE, class LOCK&gt; TYPE *<br>Singleton&lt;TYPE, LOCK&gt;::instance (void) {<br>    // First check<br>    TYPE* tmp = instance_;<br>    // Insert the CPU-specific memory barrier instruction<br>    // to synchronize the cache lines on multi-processor.<br>    asm ("memoryBarrier");<br>    if (tmp == 0) {<br>        // Ensure serialization (guard<br>        // constructor acquires lock_).<br>        Guard&lt;LOCK&gt; guard (lock_);<br>        // Double check.<br>        tmp = instance_;<br>        if (tmp == 0) {<br>                tmp = new TYPE;<br>                // Insert the CPU-specific memory barrier instruction<br>                // to synchronize the cache lines on multi-processor.<br>                asm ("memoryBarrier");<br>                instance_ = tmp;<br>        }<br>    return tmp;<br>    }<br></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<h2><a name="ThreadLocal">Fixing Double-Checked Locking using Thread Local Storage</a></h2>
<p>
Alexander Terekhov (TEREKHOV@de.ibm.com)
came up clever suggestion for implementing
double checked locking using thread local storage. Each thread
keeps a thread local flag to determine whether
that thread has done the required synchronization.
<table>
    <tbody>
        <tr>
            <td>
            <pre>  class Foo {<br>	 /** If perThreadInstance.get() returns a non-null value, this thread<br>		has done synchronization needed to see initialization<br>		of helper */<br>         private final ThreadLocal perThreadInstance = new ThreadLocal();<br>         private Helper helper = null;<br>         public Helper getHelper() {<br>             if (perThreadInstance.get() == null) createHelper();<br>             return helper;<br>         }<br>         private final void createHelper() {<br>             synchronized(this) {<br>                 if (helper == null)<br>                     helper = new Helper();<br>             }<br>	     // Any non-null value would do as the argument here<br>             perThreadInstance.set(perThreadInstance);<br>         }<br>	}<br></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>
The performance of this technique depends quite a bit on which JDK
implementation
you have. In Sun's 1.2 implementation, ThreadLocal's were very slow.
They are significantly faster in 1.3, and are expected to be faster
still in 1.4. <a href="http://www.cs.umd.edu/%7Epugh/java/memoryModel/DCL-performance.html">Doug Lea analyzed the performance of some techniques for
implementing lazy initialization</a>.
</p>
<h2>Under the new Java Memory Model</h2>
<p>As of JDK5, there is <a href="http://www.cs.umd.edu/%7Epugh/java/memoryModel">a new Java Memory Model and Thread specification</a>.
</p>
<h3>Fixing Double-Checked Locking using Volatile</h3>
<p>JDK5 and later extends the semantics for volatile so that the
system will not allow a write of a volatile to be reordered with
respect to any previous read or write, and a read of a volatile cannot
be reordered with respect to any following read or write. See <a href="http://jeremymanson.blogspot.com/2008/05/double-checked-locking.html">
this entry in Jeremy Manson's blog</a> for more details.
</p>
<p>With this change, the Double-Checked Locking idiom can be made to
work by declaring the
<tt>helper</tt> field to be volatile. This <em> does not
work</em>  under JDK4 and earlier.
</p>
<p>
<table border="2">
    <tbody>
        <tr>
            <td>
            <pre>// Works with acquire/release semantics for volatile<br>// Broken under current semantics for volatile<br>  class Foo {<br>        private volatile Helper helper = null;<br>        public Helper getHelper() {<br>            if (helper == null) {<br>                synchronized(this) {<br>                    if (helper == null)<br>                        helper = new Helper();<br>                }<br>            }<br>            return helper;<br>        }<br>    }<br></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<h3>Double-Checked Locking Immutable Objects</h3>
<p> If Helper is an immutable object, such that all of the fields of
Helper are final, then double-checked locking
will work without having to use volatile fields.
The idea is that a reference to an immutable object (such as a
String or an Integer) should behave in much the same way as an int or float;
reading and writing references to immutable objects are atomic.
</p>
<h1>Descriptions of double-check idiom</h1>
<ul>
    <li><a href="http://www.cs.wustl.edu/%7Eschmidt/editorial-3.html">Reality Check</a>,
    Douglas C. Schmidt, C++ Report, SIGS, Vol. 8, No. 3, March 1996.
    </li>
    <li>
    <a href="http://www.cs.wustl.edu/%7Eschmidt/DC-Locking.ps.gz">Double-Checked Locking:
    An Optimization Pattern for Efficiently Initializing and Accessing
    Thread-safe Objects</a>,
    Douglas Schmidt and Tim Harrison.
    <em> 3rd annual Pattern Languages of Program Design conference</em> , 1996
    </li>
    <li><a href="http://www.javaworld.com/javaworld/javatips/jw-javatip67.html">Lazy instantiation</a>, Philip Bishop and Nigel Warren, JavaWorld Magazine
    </li>
    <li><a href="http://www.javaworld.com/javaworld/jw-04-1999/jw-04-toolbox-3.html">Programming Java threads in the real world, Part 7</a>, Allen Holub,
    Javaworld Magazine, April 1999.
    </li>
    <li>
    <a href="http://www.phptr.com/ptrbooks/ptr_0130142603.html"><em> Java 2 Performance and Idiom Guide</em> </a>, Craig Larman and Rhett Guthrie, p100.
    </li>
    <li>
    <a href="http://www.google.com/search?q=Java+Design+Styles+Nigel+Bishop"><em> Java in Practice:  Design Styles and Idioms for Effective Java</em> </a>, Nigel
    Warren and Philip Bishop, p142.
    </li>
    <li>Rule 99, <a href="http://www.google.com/search?q=elements+java+style+Ambler"><em> The Elements of Java Style</em> </a>, Allan Vermeulen, Scott Ambler,
    Greg Bumgardner, Eldon Metz, Trvor Misfeldt,
    Jim Shur, Patrick Thompson, SIGS Reference library
    </li>
    <li><a href="http://gamelan.earthweb.com/journal/techfocus/022300_singleton.html">Global Variables in Java with the
    Singleton Pattern</a>, Wiebe de Jong, Gamelan
    </li>
</ul>
<br><img src ="http://www.cppblog.com/michaelgao/aggbug/64806.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-23 14:25 <a href="http://www.cppblog.com/michaelgao/archive/2008/10/23/64806.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式解析之——AbstractFactory模式</title><link>http://www.cppblog.com/michaelgao/archive/2008/10/22/64685.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Wed, 22 Oct 2008 02:44:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/10/22/64685.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/64685.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/10/22/64685.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/64685.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/64685.html</trackback:ping><description><![CDATA[<div class="posthead">
<h2>
<a id="AjaxHolder_ctl01_TitleUrl" class="singleposttitle" href="http://www.cnblogs.com/k-eckel/articles/188890.html">设计模式解析之——AbstractFactory模式（k_eckel转自微软高校博客K_eckel's mindview） </a>
</h2>
</div>
<div class="postbody">
<h1 style="margin: 17pt 0cm 16.5pt;"><font size="5">0 引言</font></h1>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">0.1 </font>目的</font></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本文档给出设计模式之——AbstractFactory模式的简化诠释，并给出其C++实现。</p>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">0.2 </font>说明</font></h2>
<div align="center">
<table class="MsoTableGrid" style="border: medium none ; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>Project</p>
            </td>
            <td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext #d4d0c8; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>Design Pattern Explanation（By K_Eckel）</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid; border-color: #d4d0c8 windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>Authorization</p>
            </td>
            <td style="border-style: none solid solid none; border-color: #d4d0c8 windowtext windowtext #d4d0c8; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>Free Distributed but Ownership Reserved</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid; border-color: #d4d0c8 windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>Date</p>
            </td>
            <td style="border-style: none solid solid none; border-color: #d4d0c8 windowtext windowtext #d4d0c8; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>
            </p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid; border-color: #d4d0c8 windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>Test Bed</p>
            </td>
            <td style="border-style: none solid solid none; border-color: #d4d0c8 windowtext windowtext #d4d0c8; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>MS Visual C++ 6.0</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">0.3 </font>参考</font></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在本文档的写作中，参考了以下的资源，在此列出表示感谢：</p>
<p>u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 书籍</p>
<p>[GoF 2000]：GoF,Design Patterns-Elements of Reusable Object-Oriented Software </p>
<p>Addison-Wesley 2000/9.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Martine 2003]：Robert C.Martine, Agile Software Development Principles, Patterns, and Practices, Pearson Education, 2003.</p>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">0.4 </font>联系作者</font></h2>
<div align="center">
<table class="MsoTableGrid" style="border: medium none ; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>Author</p>
            </td>
            <td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext #d4d0c8; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>K_Eckel</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid; border-color: #d4d0c8 windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>State</p>
            </td>
            <td style="border-style: none solid solid none; border-color: #d4d0c8 windowtext windowtext #d4d0c8; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>Candidate for Master&#8217;s Degree School of
            </p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid; border-color: #d4d0c8 windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>E_mail</p>
            </td>
            <td style="border-style: none solid solid none; border-color: #d4d0c8 windowtext windowtext #d4d0c8; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#102;&#114;&#119;&#101;&#105;&#64;&#119;&#104;&#117;&#46;&#101;&#100;&#117;&#46;&#99;&#110;">frwei@whu.edu.cn</a> &nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<h1 style="margin: 17pt 0cm 16.5pt;"><font size="5">2 AbstractFactory模式</font></h1>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">2.1 </font>问题</font></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 假设我们要开发一款游戏，当然为了吸引更多的人玩，游戏难度不能太大（让大家都没有信心了，估计游戏也就没有前途了），但是也不能太简单（没有挑战性也不符合玩家的心理）。于是我们就可以采用这样一种处理策略：为游戏设立等级，初级、中级、高级甚至有BT级。假设也是过关的游戏，每个关卡都有一些怪物（monster）守着，玩家要把这些怪
物干掉才可以过关。作为开发者，我们就不得不创建怪物的类，然后初级怪物、中级怪物等都继承自怪物类（当然不同种类的则需要另创建类，但是模式相同）。在
每个关卡，我们都要创建怪物的实例，例如初级就创建初级怪物（有很多种类）、中级创建中级怪物等。可以想象在这个系统中，将会有成千上万的怪物实例要创
建，问题是还要保证创建的时候不会出错：初级不能创建BT级的怪物（玩家就郁闷了，玩家一郁闷，游戏也就挂挂了），反之也不可以。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AbstractFactory模式就是用来解决这类问题的：要创建一组相关或者相互依赖的对象。</p>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">2.2 </font>模式选择</font></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AbstractFactory模式典型的结构图为：<br></p>
<p><img style="width: 570px; height: 504px;" src="http://www.mscenter.edu.cn/blog/images/mscenter_edu_cn/k_eckel/AbstractFactory.jpg" width="650" border="0" height="504"><br>图<font face="Times New Roman">2-1</font>：<font face="Times New Roman">AbstractFactoryPattern</font>结构图</p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AbstractFactory</font>模式关键就是将这一组对象的创建封装到一个用于创建对象的类（<font face="Times New Roman">ConcreteFactory</font>）中，维护这样一个创建类总比维护<font face="Times New Roman">n</font>多相关对象的创建过程要简单的多。</p>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">2.3 </font>实现</font></h2>
<h3 style="margin: 13pt 0cm;"><font size="3"><font face="Times New Roman">
</font></font>
<p><font size="3"><font face="Times New Roman"><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AbstractFactory</font>模式的实现比较简单，这里为了方便初学者的学习和参考，将给出完整的实现代码（所有代码采用<font face="Times New Roman">C++</font>实现，并在<font face="Times New Roman">VC 6.0</font>下测试运行）。<br></font></font></p>
<table class="MsoTableGrid" style="border: medium none ; background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid green; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <p><font face="宋体">代码片断</font>1<font face="宋体">：</font>Product.h<br>//Product.h</p>
            <p>#ifndef _PRODUCT_H_<br>#define _PRODUCT_H_</p>
            <p>class AbstractProductA<br>{<br>public:<br>&nbsp;virtual ~AbstractProductA();</p>
            <p>protected:<br>&nbsp;AbstractProductA();</p>
            <p>private:</p>
            <p>};</p>
            <p>class AbstractProductB<br>{<br>public:<br>&nbsp;virtual ~AbstractProductB();</p>
            <p>protected:<br>&nbsp;AbstractProductB();</p>
            <p>private:</p>
            <p>};</p>
            <p>class ProductA1:public AbstractProductA<br>{<br>public:<br>&nbsp;ProductA1();</p>
            <p>&nbsp;~ProductA1();</p>
            <p>protected:</p>
            <p>private:</p>
            <p>};</p>
            <p>class ProductA2:public AbstractProductA<br>{<br>public:<br>&nbsp;ProductA2();</p>
            <p>&nbsp;~ProductA2();</p>
            <p>protected:</p>
            <p>private:</p>
            <p>};</p>
            <p>class ProductB1:public AbstractProductB<br>{<br>public:<br>&nbsp;ProductB1();</p>
            <p>&nbsp;~ProductB1();</p>
            <p>protected:</p>
            <p>private:</p>
            <p>};</p>
            <p>class ProductB2:public AbstractProductB<br>{<br>public:<br>&nbsp;ProductB2();</p>
            <p>&nbsp;~ProductB2();</p>
            <p>protected:</p>
            <p>private:</p>
            <p>};</p>
            <p>#endif //~_PRODUCT_H_</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid; border-color: #d4d0c8 green green; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <p><font face="宋体">代码片断</font>2<font face="宋体">：</font>Product.cpp<br>//Product.cpp</p>
            <p>#include "Product.h"</p>
            <p>#include &lt;iostream&gt;<br>using namespace std;</p>
            <p>AbstractProductA::AbstractProductA()<br>{</p>
            <p>}</p>
            <p>AbstractProductA::~AbstractProductA()<br>{</p>
            <p>}</p>
            <p>AbstractProductB::AbstractProductB()<br>{</p>
            <p>}</p>
            <p>AbstractProductB::~AbstractProductB()<br>{</p>
            <p>}</p>
            <p>ProductA1::ProductA1()<br>{<br>&nbsp;cout&lt;&lt;"ProductA1..."&lt;&lt;endl;<br>}</p>
            <p>ProductA1::~ProductA1()<br>{</p>
            <p>}</p>
            <p>ProductA2::ProductA2()<br>{<br>&nbsp;cout&lt;&lt;"ProductA2..."&lt;&lt;endl;<br>}</p>
            <p>ProductA2::~ProductA2()<br>{</p>
            <p>}</p>
            <p>ProductB1::ProductB1()<br>{<br>&nbsp;cout&lt;&lt;"ProductB1..."&lt;&lt;endl;<br>}</p>
            <p>ProductB1::~ProductB1()<br>{</p>
            <p>}</p>
            <p>ProductB2::ProductB2()<br>{<br>&nbsp;cout&lt;&lt;"ProductB2..."&lt;&lt;endl;<br>}</p>
            <p>ProductB2::~ProductB2()<br>{</p>
            <p>}</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid; border-color: #d4d0c8 green green; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <p><font face="宋体">代码片断</font>3<font face="宋体">：</font>AbstractFactory.h<br>//AbstractFactory.h</p>
            <p>#ifndef _ABSTRACTFACTORY_H_<br>#define _ABSTRACTFACTORY_H_</p>
            <p>class AbstractProductA;<br>class AbstractProductB;</p>
            <p>class AbstractFactory<br>{<br>public:<br>&nbsp;virtual ~AbstractFactory();</p>
            <p>&nbsp;virtual AbstractProductA* CreateProductA() = 0;</p>
            <p>&nbsp;virtual AbstractProductB* CreateProductB() = 0;</p>
            <p>protected:<br>&nbsp;AbstractFactory();</p>
            <p>private:</p>
            <p>};</p>
            <p>class ConcreteFactory1:public AbstractFactory<br>{<br>public:<br>&nbsp;ConcreteFactory1();</p>
            <p>&nbsp;~ConcreteFactory1();</p>
            <p>&nbsp;AbstractProductA* CreateProductA();</p>
            <p>&nbsp;AbstractProductB* CreateProductB();</p>
            <p>protected:</p>
            <p>private:</p>
            <p>};</p>
            <p>class ConcreteFactory2:public AbstractFactory<br>{<br>public:<br>&nbsp;ConcreteFactory2();</p>
            <p>&nbsp;~ConcreteFactory2();</p>
            <p>&nbsp;AbstractProductA* CreateProductA();</p>
            <p>&nbsp;AbstractProductB* CreateProductB();</p>
            <p>protected:</p>
            <p>private:</p>
            <p>};<br>#endif //~_ABSTRACTFACTORY_H_</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid; border-color: #d4d0c8 green green; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <p><font face="宋体">代码片断</font>4<font face="宋体">：</font>AbstractFactory.cpp<br>//AbstractFactory.cpp</p>
            <p>#include "AbstractFactory.h"<br>#include "Product.h"</p>
            <p>#include &lt;iostream&gt;<br>using namespace std;</p>
            <p>AbstractFactory::AbstractFactory()<br>{</p>
            <p>}</p>
            <p>AbstractFactory::~AbstractFactory()<br>{</p>
            <p>}</p>
            <p>ConcreteFactory1::ConcreteFactory1()<br>{</p>
            <p>}</p>
            <p>ConcreteFactory1::~ConcreteFactory1()<br>{</p>
            <p>}</p>
            <p>AbstractProductA* ConcreteFactory1::CreateProductA()<br>{<br>&nbsp;return new ProductA1();<br>}</p>
            <p>AbstractProductB* ConcreteFactory1::CreateProductB()<br>{<br>&nbsp;return new ProductB1();<br>}</p>
            <p>ConcreteFactory2::ConcreteFactory2()<br>{</p>
            <p>}</p>
            <p>ConcreteFactory2::~ConcreteFactory2()<br>{</p>
            <p>}</p>
            <p>AbstractProductA* ConcreteFactory2::CreateProductA()<br>{<br>&nbsp;return new ProductA2();<br>}</p>
            <p>AbstractProductB* ConcreteFactory2::CreateProductB()<br>{<br>&nbsp;return new ProductB2();<br>}</p>
            </td>
        </tr>
        <tr>
            <td style="border-style: none solid solid; border-color: #d4d0c8 green green; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <p><font face="宋体">代码片断</font>5<font face="宋体">：</font>main.cpp<br>//main.cpp</p>
            <p>#include "AbstractFactory.h"</p>
            <p>#include &lt;iostream&gt;<br>using namespace std;</p>
            <p>int main(int argc,char* argv[])<br>{<br>&nbsp;AbstractFactory* cf1 = new ConcreteFactory1();</p>
            <p>&nbsp;cf1-&gt;CreateProductA();<br>&nbsp;cf1-&gt;CreateProductB();</p>
            <p>&nbsp;AbstractFactory* cf2 = new ConcreteFactory2();<br>&nbsp;cf2-&gt;CreateProductA();<br>&nbsp;cf2-&gt;CreateProductB();</p>
            <p>&nbsp;return 0;<br>}</p>
            </td>
        </tr>
    </tbody>
</table>
</h3>
<h3 style="margin: 13pt 0cm;"><font size="3"><font face="Times New Roman"><font size="3">
</font></font></font>
<p><font size="3"><font face="Times New Roman"><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AbstractFactory模式的实现代码很简单，在测试程序中可以看到，当我们要创建一组对象（ProductA1，ProductA2）的时候我们只用维护一个创建对象（ConcreteFactory1），大大简化了维护的成本和工作。</font></font></font></p>
</h3>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Times New Roman"><font size="3"><font size="3"><font face="Arial">2.4 </font>讨论</font></font></font></font></h2>
<p><font size="3"><font face="Times New Roman"><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AbstractFactory模式和Factory模式的区别是初学（使用）设计模式时候的一个容易引起困惑的地方。实际上，AbstractFactory模式是为创建<strong>一组（有多类）</strong>相关或依赖的对象提供创建接口，而Factory模式正如我在相应的文档中分析的是为<strong>一类</strong>对象提供创建接口或延迟对象的创建到子类中实现。并且可以看到，AbstractFactory模式通常都是使用Factory模式实现（ConcreteFactory1）。</font></font></font></p>
</div>
<font size="3"><font face="Times New Roman"><font size="3">	</font></font></font><br><img src ="http://www.cppblog.com/michaelgao/aggbug/64685.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-22 10:44 <a href="http://www.cppblog.com/michaelgao/archive/2008/10/22/64685.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编辑decorate程序时遇到一个问题</title><link>http://www.cppblog.com/michaelgao/archive/2008/10/16/64170.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Thu, 16 Oct 2008 09:04:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/10/16/64170.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/64170.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/10/16/64170.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/64170.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/64170.html</trackback:ping><description><![CDATA[class Decorator:public Beverage<br>{<br>&nbsp;&nbsp;&nbsp; public:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Decorator(Beverage * com);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual ~Decorator();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual string get_descrption();<br>&nbsp;&nbsp;&nbsp;<span style="background-color: yellow;"> protected:</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background-color: yellow;">&nbsp; Beverage * component;</span><br><br><br>};<br><br>
而MilkDecorator继承了Decorator,如果component 为私有的则MilkDecorator便不能访问。<br><br>如果milkDecorator 设计成这样就不会违反了封装的原则。<br>基本上只有一个区别，就是protect成员能被派生类访问！而派生类对private没有特殊访问权！
<br><br><img src ="http://www.cppblog.com/michaelgao/aggbug/64170.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-16 17:04 <a href="http://www.cppblog.com/michaelgao/archive/2008/10/16/64170.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UML中一些符号的意义</title><link>http://www.cppblog.com/michaelgao/archive/2008/10/13/63889.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Mon, 13 Oct 2008 06:53:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/10/13/63889.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/63889.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/10/13/63889.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/63889.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/63889.html</trackback:ping><description><![CDATA[<div><font face="Verdana">http://book.csdn.net/bookfiles/575/10057518902.shtml<br><br>虚线箭头表示&#8220;依赖关系&#8221;，依赖有&#8220;使用&#8221;的语义，比如患者与医生的关系。<br>实线箭头表示&#8220;带了导航行的关联关系&#8221;，从一个类到另一类。<br>使用实线箭头时通常会带上&#8220;多重性&#8221;的表达方式。如：一对多，一对一，多对多等等
<br><br>常见的关系有：一般化关系（Generalization），关联关系（Association），聚合关系（Aggregation），合成关系（Composition），依赖关系（Dependency）。</font>
<p><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中，聚合关系（Aggregation），合成关系（Composition）属于关联关系（Association）。</font></p>
<p><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般关系表现为继承或实现关系(is a)，关联关系表现为变量(has a )，依赖关系表现为函数中的参数(use a)。</font></p>
<p><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般化关系：表示为类与类之间的继承关系，接口与接口之间的继承，类对接口的实现关系。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示方法： 用一个空心箭头＋实线，箭头指向父类。或空心箭头＋虚线，如果父类是接口。</font></p>
<p><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关联关系：类与类之间的联接，它使一个类知道另一个类的属性和方法。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示方法：用 实线＋箭头， 箭头指向被使用的类。</font></p>
<p><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 聚合关系：是关联关系的一种，是强的关联关系。聚合关系是整体和个体的关系。关联关系的两个类处于同一层次上，啊聚合关系两个类处于不同的层次，一个是整体，一个是部分。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示方法：空心菱形＋实线＋箭头，箭头指向部分。</font></p>
<p><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 合成关系：是关联关系的一种，是比聚合关系强的关系。它要求普通的聚合关系中代表整体的<a href="http://www.itisedu.com/phrase/200603090845215.html" target="_new"><font color="#0000ff"><u>对象</u></font></a>负责代表部分的对象的生命周期，合成关系不能共享。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示方法：实心菱形＋实线＋箭头，</font></p>
<p><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 依赖关系：是类与类之间的连接，表示一个类依赖于另一个类的定义。例如如果A依赖于B，则B体现为局部变量，方法的参数、或静态方法的调用。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示方法：虚线＋箭头</font></p>
</div>
<br>图一:<br><br>
<div style="width: 100%; overflow-x: auto;"><a href="http://www.azure.com.cn/uploads/200706/04_211918_1121523.jpg" target="_blank"><img src="http://www.azure.com.cn/uploads/200706/04_211918_1121523.jpg" alt="uploads/200706/04_211918_1121523.jpg"></a></div>
<br><br>此实线箭头表示, 继承, 从一个非接口类的继承.<br><br>图二:<br>
<div style="width: 100%; overflow-x: auto;"><a href="http://www.azure.com.cn/uploads/200706/04_212112_1121525gl.jpg" target="_blank"><img src="http://www.azure.com.cn/uploads/200706/04_212112_1121525gl.jpg" alt="uploads/200706/04_212112_1121525gl.jpg"></a></div>
<br><br>那条连线表示双向关联:<br>看左边, Flight扮演assignedFights角色, 有0到1个Plane跟他关联(一个航班要么取消了没有飞机,要么只能对应一架飞机)<br>看右边, Plane扮演着assignedPlane角色,  有0到多个Flight跟他关联(一个飞机可以参与多个航班, 也可以停在仓库里面烂掉)<br><br>图三:<br>
<div style="width: 100%; overflow-x: auto;"><a href="http://www.azure.com.cn/uploads/200706/04_213002_1121526dxgl.jpg" target="_blank"><img src="http://www.azure.com.cn/uploads/200706/04_213002_1121526dxgl.jpg" alt="uploads/200706/04_213002_1121526dxgl.jpg"></a></div>
<br><br>那条连线表示单向关联:<br>基本的意义跟上面的是一样的, 唯一不同的是, 右边的类对左边的类是一无所知的.<br><br>图四:<br>
<div style="width: 100%; overflow-x: auto;"><a href="http://www.azure.com.cn/uploads/200706/04_213232_1121527rjb.jpg" target="_blank"><img src="http://www.azure.com.cn/uploads/200706/04_213232_1121527rjb.jpg" alt="uploads/200706/04_213232_1121527rjb.jpg"></a></div>
<br><br>那个大的包围的框叫软件包, 名字为Account, 就一些可以归类的类包装起来.<br><br>图五:<br>
<div style="width: 100%; overflow-x: auto;"><a href="http://www.azure.com.cn/uploads/200706/04_213441_1121529xjc.gif" target="_blank"><img src="http://www.azure.com.cn/uploads/200706/04_213441_1121529xjc.gif" alt="uploads/200706/04_213441_1121529xjc.gif"></a></div>
<br><br>如此虚线的箭头表示实现一个接口.<br><br>图六:<br>
<div style="width: 100%; overflow-x: auto;"><a href="http://www.azure.com.cn/uploads/200706/04_213626_11215210gll.jpg" target="_blank"><img src="http://www.azure.com.cn/uploads/200706/04_213626_11215210gll.jpg" alt="uploads/200706/04_213626_11215210gll.jpg"></a></div>
<br><br>水平的连线还是表示上面所说的关联, 但从关联连线中引伸出来的虚线, 这意味当Flight类的一个实例关联到 FrequentFlyer 类的一个实例时，将会产生 MileageCredit 类的一个实例.<br><br>图七:<br>
<div style="width: 100%; overflow-x: auto;"><a href="http://www.azure.com.cn/uploads/200706/04_213911_11215211jbjh.jpg" target="_blank"><img src="http://www.azure.com.cn/uploads/200706/04_213911_11215211jbjh.jpg" alt="uploads/200706/04_213911_11215211jbjh.jpg"></a></div>
<br><br>带菱形的箭头表示基本聚合, 由上图知道, Wheel类扮演wheels角色, 聚合4个到Car对象里面去,<br>空心的菱形表示Wheel对象并不随Car的创建而创建,销毁而销毁.<br><br>图八:<br>
<div style="width: 100%; overflow-x: auto;"><a href="http://www.azure.com.cn/uploads/200706/04_214248_11215212zhjh.jpg" target="_blank"><img src="http://www.azure.com.cn/uploads/200706/04_214248_11215212zhjh.jpg" alt="uploads/200706/04_214248_11215212zhjh.jpg"></a></div>
<br><br>意义和上面类似, 唯一不同的是, 实心菱形表示Department对象随Company对象的创建而创建,销毁而销毁.<br><br>图九:<br>
<div style="width: 100%; overflow-x: auto;"><a href="http://www.azure.com.cn/uploads/200706/04_214435_11215213fs.gif" target="_blank"><img src="http://www.azure.com.cn/uploads/200706/04_214435_11215213fs.gif" alt="uploads/200706/04_214435_11215213fs.gif"></a></div>
<br><br>表示反射关联, 显示一个Employee类如何通过manager / manages角色与它本身相关。当一个类关联到它本身时，这并不意味着类的实例与它本身相关，而是类的一个实例与类的另一个实例相关。<br>
<br>  <img src ="http://www.cppblog.com/michaelgao/aggbug/63889.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-13 14:53 <a href="http://www.cppblog.com/michaelgao/archive/2008/10/13/63889.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式解析之——Observer模式（k_eckel转自微软高校博客K_eckel's mindview） </title><link>http://www.cppblog.com/michaelgao/archive/2008/10/10/63633.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Fri, 10 Oct 2008 03:04:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/10/10/63633.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/63633.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/10/10/63633.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/63633.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/63633.html</trackback:ping><description><![CDATA[<div class="posthead">
<h2>
<a id="AjaxHolder_ctl01_TitleUrl" class="singleposttitle" href="http://www.cnblogs.com/k-eckel/articles/188889.html">设计模式解析之——Observer模式（k_eckel转自微软高校博客K_eckel's mindview） </a>
</h2>
</div>
<div class="postbody">
<h1 style="margin: 17pt 0cm 16.5pt;"><font size="5">0 引言</font></h1>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">0.1 </font>目的</font></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本文档给出设计模式之——Observer模式的简化诠释，并给出其C++实现。</p>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">0.2 </font>说明</font></h2>
<div align="center">
<table class="MsoTableGrid" style="border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>Project</p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>Design Pattern Explanation（By K_Eckel）</p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>Authorization</p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>Free Distributed but Ownership Reserved</p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>Date</p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>
            </p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>Test Bed</p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>MS Visual C++ 6.0</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">0.3 </font>参考</font></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在本文档的写作中，参考了以下的资源，在此列出表示感谢：</p>
<p>u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 书籍</p>
<p>[GoF 2000]：GoF,Design Patterns-Elements of Reusable Object-Oriented Software </p>
<p>Addison-Wesley 2000/9.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Martine 2003]：Robert C.Martine, Agile Software Development Principles, Patterns, and Practices, Pearson Education, 2003.</p>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">0.4 </font>联系作者</font></h2>
<div align="center">
<table class="MsoTableGrid" style="border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>Author</p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>K_Eckel</p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>State</p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p>Candidate for Master&#8217;s Degree School of
            </p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; background: silver none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 86.4pt;" valign="top" width="115">
            <p>E_mail</p>
            </td>
            <td style="padding: 0cm 5.4pt; width: 339.7pt; background-color: transparent;" valign="top" width="453">
            <p><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#102;&#114;&#119;&#101;&#105;&#64;&#119;&#104;&#117;&#46;&#101;&#100;&#117;&#46;&#99;&#110;">frwei@whu.edu.cn</a> &nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<h1 style="margin: 17pt 0cm 16.5pt;"><font size="5">2 Observer模式</font></h1>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">2.1 </font>问题</font></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Observer模式应该可以说是应用最多、影响最广的模式之一，因为Observer的一个实例Model/View/Control（MVC）结构在系统开发架构设计中有着很重要的地位和意义，MVC实现了业务逻辑和表示层的解耦。<strong>个人也认为</strong><strong>Observer</strong><strong>模式是软件开发过程中必须要掌握和使用的模式之一</strong>。在MFC中，Doc/View（文档视图结构）提供了实现MVC的框架结构（有一个从设计模式（Observer模式）的角度分析分析Doc/View的文章正在进一步的撰写当中，遗憾的是时间：））。在Java阵容中，Struts则提供和MFC中Doc/View结构类似的实现MVC的框架。另外Java语言本身就提供了Observer模式的实现接口，这将在讨论中给出。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然，MVC只是Observer模式的一个实例。Observer模式要解决的问题为：建立一个一（Subject）对多（Observer）
的依赖关系，并且做到当&#8220;一&#8221;变化的时候，依赖这个&#8220;一&#8221;的多也能够同步改变。最常见的一个例子就是：对同一组数据进行统计分析时候，我们希望能够提供多
种形式的表示（例如以表格进行统计显示、柱状图统计显示、百分比统计显示等）。这些表示都依赖于同一组数据，我们当然需要当数据改变的时候，所有的统计的
显示都能够同时改变。Observer模式就是解决了这一个问题。</p>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">2.2 </font>模式选择</font></h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Observer模式典型的结构图为：<br></p>
<p><img style="width: 604px; height: 312px;" src="http://www.mscenter.edu.cn/blog/images/mscenter_edu_cn/k_eckel/Observer.jpg" width="650" border="0" height="312"><br>图<font face="Times New Roman">2-1</font>：<font face="Times New Roman">Observer Pattern</font>结构图</p>
<p><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font>这里的目标<font face="Times New Roman">Subject</font>提供依赖于它的观察者<font face="Times New Roman">Observer</font>的注册（<font face="Times New Roman">Attach</font>）和注销（<font face="Times New Roman">Detach</font>）操作，并且提供了使得依赖于它的所有观察者同步的操作（<font face="Times New Roman">Notify</font>）。观察者<font face="Times New Roman">Observer</font>则提供一个<font face="Times New Roman">Update</font>操作，注意这里的<font face="Times New Roman">Observer</font>的<font face="Times New Roman">Update</font>操作并不在<font face="Times New Roman">Observer</font>改变了<font face="Times New Roman">Subject</font>目标状态的时候就对自己进行更新，这个更新操作要延迟到<font face="Times New Roman">Subject</font>对象发出<font face="Times New Roman">Notify</font>通知所有<font face="Times New Roman">Observer</font>进行修改（调用<font face="Times New Roman">Update</font>）。</p>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Arial">2.3 </font>实现</font></h2>
<h3 style="margin: 13pt 0cm;"><font size="3"><font face="Times New Roman">
</font></font>
<p><font size="3"><font face="Times New Roman"><font face="Times New Roman">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Observer</font>模式的实现有些特点，这里为了方便初学者的学习和参考，将给出完整的实现代码（所有代码采用<font face="Times New Roman">C++</font>实现，并在<font face="Times New Roman">VC 6.0</font>下测试运行）。<br></font></font></p>
<table class="MsoTableGrid" style="background: #d9d9d9 none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <p><font face="宋体">代码片断</font>1<font face="宋体">：</font>Subject.h<br>//Subject.h</p>
            <p>#ifndef _SUBJECT_H_<br>#define _SUBJECT_H_</p>
            <p>#include &lt;list&gt;<br>#include &lt;string&gt;<br>using namespace std;</p>
            <p>typedef string State;</p>
            <p>class Observer;</p>
            <p>class Subject<br>{<br>public:<br>&nbsp;virtual ~Subject();</p>
            <p>&nbsp;virtual void Attach(Observer* obv);</p>
            <p>&nbsp;virtual void Detach(Observer* obv);</p>
            <p>&nbsp;virtual void Notify();</p>
            <p>&nbsp;virtual void SetState(const State&amp; st) = 0;</p>
            <p>&nbsp;virtual State GetState() = 0;</p>
            <p>protected:<br>&nbsp;Subject();</p>
            <p>private:<br>&nbsp;list&lt;Observer* &gt;* _obvs;</p>
            <p>};</p>
            <p>class ConcreteSubject:public Subject<br>{<br>public:<br>&nbsp;ConcreteSubject();</p>
            <p>&nbsp;~ConcreteSubject();</p>
            <p>&nbsp;State GetState();</p>
            <p>&nbsp;void SetState(const State&amp; st);</p>
            <p>protected:</p>
            <p>private:<br>&nbsp;State _st;</p>
            <p>};</p>
            <p>#endif //~_SUBJECT_H_</p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <p><font face="宋体">代码片断</font>2<font face="宋体">：</font>Subject.cpp<br>//Subject.cpp</p>
            <p>#include "Subject.h"<br>#include "Observer.h"</p>
            <p>#include &lt;iostream&gt;<br>#include &lt;list&gt;<br>using namespace std;</p>
            <p>typedef string state;</p>
            <p>Subject::Subject()<br>{<br>&nbsp;//****<font face="宋体">在模板的使用之前一定要</font>new<font face="宋体">，创建</font><br>&nbsp;_obvs = new list&lt;Observer*&gt;;</p>
            <p>}</p>
            <p>Subject::~Subject()<br>{<br>&nbsp;<br>}</p>
            <p>void Subject::Attach(Observer* obv)<br>{<br>&nbsp;<br>&nbsp;_obvs-&gt;push_front(obv);<br>}</p>
            <p>void Subject::Detach(Observer* obv)<br>{<br>&nbsp;if (obv != NULL)<br>&nbsp;&nbsp;_obvs-&gt;remove(obv);<br>}</p>
            <p>void Subject::Notify()<br>{<br>&nbsp;<br>&nbsp;list&lt;Observer*&gt;::iterator it;</p>
            <p>&nbsp;it = _obvs-&gt;begin();</p>
            <p>&nbsp;for (;it != _obvs-&gt;end();it++)<br>&nbsp;{<br>&nbsp;&nbsp;//<font face="宋体">关于模板和</font>iterator<font face="宋体">的用法</font></p>
            <p>&nbsp;&nbsp;(*it)-&gt;Update(this);<br>&nbsp;}<br>}</p>
            <p>ConcreteSubject::ConcreteSubject()<br>{<br>&nbsp;_st = '\0';<br>}</p>
            <p>ConcreteSubject::~ConcreteSubject()<br>{<br>&nbsp;<br>}</p>
            <p><br>State ConcreteSubject::GetState()<br>{<br>&nbsp;return _st;<br>}</p>
            <p>void ConcreteSubject::SetState(const State&amp; st)<br>{<br>&nbsp;_st = st;<br>}</p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <p><font face="宋体">代码片断</font>3<font face="宋体">：</font>Observer.h<br>//Observer.h</p>
            <p>#ifndef _OBSERVER_H_<br>#define _OBSERVER_H_</p>
            <p>#include "Subject.h"</p>
            <p>#include &lt;string&gt;<br>using namespace std;</p>
            <p>typedef string State;</p>
            <p>class Observer<br>{<br>public:<br>&nbsp;virtual ~Observer();</p>
            <p>&nbsp;virtual void Update(Subject* sub) = 0;</p>
            <p>&nbsp;virtual void PrintInfo() = 0;</p>
            <p>protected:<br>&nbsp;Observer();</p>
            <p>&nbsp;State _st;</p>
            <p>private:</p>
            <p>};</p>
            <p>class ConcreteObserverA:public Observer<br>{<br>public:<br>&nbsp;virtual Subject* GetSubject();<br>&nbsp;<br>&nbsp;ConcreteObserverA(Subject* sub);</p>
            <p>&nbsp;virtual ~ConcreteObserverA();</p>
            <p>&nbsp;//<font face="宋体">传入</font>Subject<font face="宋体">作为参数，这样可以让一个</font>View<font face="宋体">属于多个的</font>Subject<font face="宋体">。</font><br>&nbsp;void&nbsp; Update(Subject* sub);</p>
            <p>&nbsp;void PrintInfo();</p>
            <p>protected:</p>
            <p>private:<br>&nbsp;Subject* _sub;</p>
            <p>};</p>
            <p>class ConcreteObserverB:public Observer<br>{<br>public:<br>&nbsp;virtual Subject* GetSubject();<br>&nbsp;<br>&nbsp;ConcreteObserverB(Subject* sub);</p>
            <p>&nbsp;virtual ~ConcreteObserverB();</p>
            <p>&nbsp;//<font face="宋体">传入</font>Subject<font face="宋体">作为参数，这样可以让一个</font>View<font face="宋体">属于多个的</font>Subject<font face="宋体">。</font><br>&nbsp;void&nbsp; Update(Subject* sub);</p>
            <p>&nbsp;void PrintInfo();</p>
            <p>protected:</p>
            <p>private:<br>&nbsp;Subject* _sub;</p>
            <p>};</p>
            <p>#endif //~_OBSERVER_H_</p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <p><font face="宋体">代码片断</font>4<font face="宋体">：</font>Observer.cpp<br>//Observer.cpp</p>
            <p>#include "Observer.h"<br>#include "Subject.h"</p>
            <p>#include &lt;iostream&gt;<br>#include &lt;string&gt;<br>using namespace std;</p>
            <p>Observer::Observer()<br>{<br>&nbsp;_st = '\0';</p>
            <p>}</p>
            <p>Observer::~Observer()<br>{</p>
            <p>}</p>
            <p><br>ConcreteObserverA::ConcreteObserverA(Subject* sub)<br>{<br>&nbsp;_sub = sub;</p>
            <p>&nbsp;_sub-&gt;Attach(this);<br>}</p>
            <p>ConcreteObserverA::~ConcreteObserverA()<br>{<br>&nbsp;_sub-&gt;Detach(this);</p>
            <p>&nbsp;if (_sub != 0)<br>&nbsp;{<br>&nbsp;&nbsp;delete _sub;<br>&nbsp;}<br>}</p>
            <p>Subject* ConcreteObserverA::GetSubject()<br>{&nbsp;<br>&nbsp;return _sub;<br>}</p>
            <p>void ConcreteObserverA::PrintInfo()<br>{<br>&nbsp;cout&lt;&lt;"ConcreteObserverA observer.... "&lt;&lt;_sub-&gt;GetState()&lt;&lt;endl;<br>}</p>
            <p>void ConcreteObserverA::Update(Subject* sub)<br>{<br>&nbsp;_st = sub-&gt;GetState();</p>
            <p>&nbsp;PrintInfo();<br>}</p>
            <p>ConcreteObserverB::ConcreteObserverB(Subject* sub)<br>{<br>&nbsp;_sub = sub;</p>
            <p>&nbsp;_sub-&gt;Attach(this);<br>}</p>
            <p>ConcreteObserverB::~ConcreteObserverB()<br>{<br>&nbsp;_sub-&gt;Detach(this);</p>
            <p>&nbsp;if (_sub != 0)<br>&nbsp;{<br>&nbsp;&nbsp;delete _sub;<br>&nbsp;}<br>}</p>
            <p>Subject* ConcreteObserverB::GetSubject()<br>{&nbsp;<br>&nbsp;return _sub;<br>}</p>
            <p>void ConcreteObserverB::PrintInfo()<br>{<br>&nbsp;cout&lt;&lt;"ConcreteObserverB observer.... "&lt;&lt;_sub-&gt;GetState()&lt;&lt;endl;<br>}</p>
            <p>void ConcreteObserverB::Update(Subject* sub)<br>{<br>&nbsp;_st = sub-&gt;GetState();</p>
            <p>&nbsp;PrintInfo();<br>}</p>
            </td>
        </tr>
        <tr>
            <td style="padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <p><font face="宋体">代码片断</font>5<font face="宋体">：</font>main.cpp<br>//main.cpp</p>
            <p>#include "Subject.h"<br>#include "Observer.h"</p>
            <p>#include &lt;iostream&gt;<br>using namespace std;</p>
            <p>int main(int argc,char* argv[])<br>{<br>&nbsp;ConcreteSubject* sub = new ConcreteSubject();</p>
            <p>&nbsp;Observer* o1 = new ConcreteObserverA(sub);</p>
            <p>&nbsp;Observer* o2 = new ConcreteObserverB(sub);</p>
            <p>&nbsp;sub-&gt;SetState("old");</p>
            <p>&nbsp;sub-&gt;Notify();</p>
            <p>&nbsp;sub-&gt;SetState("new"); //<font face="宋体">也可以由</font>Observer<font face="宋体">调用</font></p>
            <p>&nbsp;sub-&gt;Notify();</p>
            <p>&nbsp;return 0;<br>}</p>
            </td>
        </tr>
    </tbody>
</table>
</h3>
<h3 style="margin: 13pt 0cm;"><font size="3"><font face="Times New Roman"><font size="3">
</font></font></font>
<p><font size="3"><font face="Times New Roman"><font size="3">在Observer模式的实现中，Subject维护一个list作为存储其所有观察者的容器。每当调用Notify操作就遍历list中的Observer对象，并广播通知改变状态（调用Observer的Update操作）。目标的状态state可以由Subject自己改变（示例），也可以由Observer的某个操作引起state的改变（可调用Subject的SetState操作）。Notify操作可以由Subject目标主动广播（示例），也可以由Observer观察者来调用（因为Observer维护一个指向Subject的指针）。</font></font></font></p>
<p><font size="3"><font face="Times New Roman"><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行示例程序，可以看到当Subject处于状态&#8220;old&#8221;时候，依赖于它的两个观察者都显示&#8220;old&#8221;，当目标状态改变为&#8220;new&#8221;的时候，依赖于它的两个观察者也都改变为&#8220;new&#8221;。</font></font></font></p>
</h3>
<h2 style="margin: 13pt 0cm;"><font size="3"><font face="Times New Roman"><font size="3"><font size="3"><font face="Arial">2.4 </font>讨论</font></font></font></font></h2>
<p><font size="3"><font face="Times New Roman"><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Observer是影响极为深远的模式之一，也是在大型系统开发过程中要用到的模式之一。除了MFC、Struts提供了MVC的实现框架，在Java语言中还提供了专门的接口实现Observer模式：通过专门的类Observable及Observer接口来实现MVC编程模式，其UML图可以表示为：</font></font></font></p>
<p>&nbsp;</p>
<p><font size="3"><font face="Times New Roman"><font size="3"><img src="http://www.mscenter.edu.cn/blog/images/mscenter_edu_cn/k_eckel/observer3.jpg" width="507" border="0" height="203"><br>Java中实现MVC的UML图。</font></font></font></p>
<p><font size="3"><font face="Times New Roman"><font size="3">这里的Observer就是观察者，Observable则充当目标Subject的角色。</font></font></font></p>
<p><font size="3"><font face="Times New Roman"><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Observer模式也称为发布－订阅（publish-subscribe），目标就是通知的发布者，观察者则是通知的订阅者（接受通知）。</font></font></font></p>
</div>
<font size="3"><font face="Times New Roman"><font size="3">	</font></font></font><br> <img src ="http://www.cppblog.com/michaelgao/aggbug/63633.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-10 11:04 <a href="http://www.cppblog.com/michaelgao/archive/2008/10/10/63633.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中接口与实现的分离句柄类</title><link>http://www.cppblog.com/michaelgao/archive/2008/10/07/63401.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Tue, 07 Oct 2008 08:13:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/10/07/63401.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/63401.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/10/07/63401.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/63401.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/63401.html</trackback:ping><description><![CDATA[<pre>
<div>句柄类是存储和管理基类指针的一个类 <br> 需要句柄类的背景： <br> 1）在对安全要求很高的领域，即使核心实现已经封闭在库中不可见，但头文件中变量定义仍可能曝露一些内部信息 <br> 2）在设计初期、实现部分会经常变动，甚至头文件中变量定义也需要经常变动，因此在重编译的时候头文件也需要编译，<br>有时候导致编译时间过长。<br> 句柄类就是为了解决这类问题
<br>// Handle.h<br>class Implement; //这里是对真正实现功能的类的声明<br><br>class ImplementHandle //这是Implement类的句柄类<br>{<br>public:<br>ImplementHandle():lpImplementInstance(NULL){lpImplementInstance = new Implement;}<br>~ImplementHandle(){ delete lpImplementInstance ;}<br>public:<br>// Interface_FOO() 是句柄类提供的接口，它的真正实现是在Implement类里面,而这个仅仅是接口"代理"<br>RE_TYPE Interface_FOO()<br>{<br>return lpImplementInstance-&gt;FOO
<div style="border: 1px solid #666666;">_</div>
Implementation(); //句柄代理调用实现真正的FOO接口<br>}<br>//还有其他的接口也一样，均是用句柄类代理接口<br>//....<br>private:<br>Implement * lpImplementInstance; //这个是句柄类唯一的数据成员(当然，并不一定),可以被句柄类很好地自动管理<br>};<br><br><br><br><br>&nbsp; 被封装在句柄类里面的真正实现（class Implement）将与用户隔离开来，就是说，就算以后Implement 类的实现有所改变，<br>只要它提供的接口不变，那么它的句柄类就不会改变，而包含句柄类的用户，也不用做任何相应的改变（所有包含 &#8220;Handle.h&#8221;的模块甚至不用从新编译就可以正常更新至最新的Implement实现）。<br><br>例如<br>    #include "Handle.h"<br>    Imlementhandle testhandle;<br>    testhandle-&gt;Interface_Foo();//调用接口即可。<br>    如果改动了Implent类的方法<br><br>&nbsp; 于此相反，如果直接用class Implement 的定义，那么只要Implement类的定义有所改变（不管是public 还是private 成员<br>的更新），那么所有包含它的头文件的模块都要从新编译一次。<br><br>这其实就是接口与实现的分离，
<br></div>
<br></pre>
<br> <img src ="http://www.cppblog.com/michaelgao/aggbug/63401.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-07 16:13 <a href="http://www.cppblog.com/michaelgao/archive/2008/10/07/63401.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++实现设计模式中的Interface from goolge</title><link>http://www.cppblog.com/michaelgao/archive/2008/10/07/63392.html</link><dc:creator>micheal's tech</dc:creator><author>micheal's tech</author><pubDate>Tue, 07 Oct 2008 06:39:00 GMT</pubDate><guid>http://www.cppblog.com/michaelgao/archive/2008/10/07/63392.html</guid><wfw:comment>http://www.cppblog.com/michaelgao/comments/63392.html</wfw:comment><comments>http://www.cppblog.com/michaelgao/archive/2008/10/07/63392.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/michaelgao/comments/commentRss/63392.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/michaelgao/services/trackbacks/63392.html</trackback:ping><description><![CDATA[Classes that satisfy certain conditions are allowed, but not required, to
end with an <code>Interface</code> suffix.
<br><a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Interfaces#Interfaces">
link
</a>
<p>Definition:
</p>
<p>
A class is a pure interface if it meets the following requirements:
</p>
<ul>
    <li> It has only public pure virtual ("<code>= 0</code>") methods
    and static methods (but see below for destructor).
    </li>
    <li> It may not have non-static data members.
    </li>
    <li> It need not have any constructors defined.  If a constructor is
    provided, it must take no arguments and it must be protected.
    </li>
    <li> If it is a subclass, it may only be derived from classes
    that satisfy these conditions and are tagged with the
    <code>Interface</code> suffix.
    </li>
</ul>
<p>
An interface class can never be directly instantiated
because of the pure virtual method(s) it declares.  To make
sure all implementations of the interface can be destroyed
correctly, they must also declare a virtual destructor (in
an exception to the first rule, this should not be pure).  See
Stroustrup, <cite>The C++ Programming Language</cite>, 3rd
edition, section 12.4 for details.
</p>
<p>Pros:
Tagging a class with the <code>Interface</code> suffix lets
others know that they must not add implemented methods or non
static data members.  This is particularly important in the case of
<a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Multiple_Inheritance">multiple inheritance</a>.
Additionally, the interface concept is already well-understood by
Java programmers.
</p>
<p>Cons:
The <code>Interface</code> suffix lengthens the class name, which
can make it harder to read and understand.  Also, the interface
property may be considered an implementation detail that shouldn't
be exposed to clients.
</p>
<p>Decision:
A class may end with <code>Interface</code> only if it meets the
above requirements.  We do not require the converse, however:
classes that meet the above requirements are not required to end
with <code>Interface</code>.
</p>
<br> <img src ="http://www.cppblog.com/michaelgao/aggbug/63392.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-07 14:39 <a href="http://www.cppblog.com/michaelgao/archive/2008/10/07/63392.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>