??xml version="1.0" encoding="utf-8" standalone="yes"?>7国产欧美日韩综合天堂中文久久久久 ,色婷婷综合久久久中文字幕 ,99精品国产99久久久久久97http://www.shnenglu.com/michaelgao/category/8288.htmlzh-cnWed, 07 Jan 2009 01:25:19 GMTWed, 07 Jan 2009 01:25:19 GMT60C++完美实现Singleton模式http://www.shnenglu.com/michaelgao/archive/2009/01/06/71345.htmlmicheal's techmicheal's techTue, 06 Jan 2009 08:06:00 GMThttp://www.shnenglu.com/michaelgao/archive/2009/01/06/71345.htmlhttp://www.shnenglu.com/michaelgao/comments/71345.htmlhttp://www.shnenglu.com/michaelgao/archive/2009/01/06/71345.html#Feedback2http://www.shnenglu.com/michaelgao/comments/commentRss/71345.htmlhttp://www.shnenglu.com/michaelgao/services/trackbacks/71345.html
大家都知道,在用C++来实现Singleton模式的时候通常把构造函数声明ؓU有的或者保护的。同时声明一个公有的静态的伪构造函敎ͼ通过它来调用真正的构造函数。在实现q个伪构造函数的时候通常有两U方式:  
  class   Singleton;  
   
  static   Singleton&   Singleton:;fakeSingleton()  
  {  
          static   Singleton   s;  
          return   s;  
  }  
  W二U方?  
  class   Singleton{  
  public:  
  static   Singleton*   fakeSingleton();  
  ...  
  private:  
  Singleton();  
  static   Singleton   *   _instance;  
  }  
  Singleton*   Singleton::fakesinketon()  
  {  
        if(   _instance==NULL)  
                  _instance=new   Singleton();  
          return   _instance;  
  }  
  对于q两U方式我觉得W一U更好一些,理由是,如果有两个以上的U程同时讉K伪构造函数的时候有可能同时q入if   控制块,q样有可能产生两个实例Q!因此必须采用Ҏ的保护机制来控制同步。而第一U方式不存在q样的问题? 
   
  请高手指点!我不明白的是Qؓ什么书上的例子q较多的采用W二U方法?莫非它有自己的优势?Q? 
   


micheal's tech 2009-01-06 16:06 发表评论
]]>
The "Double-Checked Locking is Broken" Declaration sigleleton 模式http://www.shnenglu.com/michaelgao/archive/2008/10/23/64806.htmlmicheal's techmicheal's techThu, 23 Oct 2008 06:25:00 GMThttp://www.shnenglu.com/michaelgao/archive/2008/10/23/64806.htmlhttp://www.shnenglu.com/michaelgao/comments/64806.htmlhttp://www.shnenglu.com/michaelgao/archive/2008/10/23/64806.html#Feedback0http://www.shnenglu.com/michaelgao/comments/commentRss/64806.htmlhttp://www.shnenglu.com/michaelgao/services/trackbacks/64806.html The "Double-Checked Locking is Broken" Declaration

Signed by : David Bacon (IBM Research) Joshua Bloch (Javasoft), Jeff Bogda, Cliff Click (Hotspot JVM project), Paul Haahr, Doug Lea, Tom May, Jan-Willem Maessen, Jeremy Manson, John D. Mitchell (jGuru) Kelvin Nilsen, Bill Pugh, Emin Gun Sirer

Double-Checked Locking is widely cited and used as an efficient method for implementing lazy initialization in a multithreaded environment.

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.

To first explain the desired behavior, consider the following code:

// Single threaded version
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null)
helper = new Helper();
return helper;
}
// other functions and members...
}

If this code was used in a multithreaded context, many things could go wrong. Most obviously, two or more Helper objects could be allocated. (We'll bring up other problems later). The fix to this is simply to synchronize the getHelper() method:

// Correct multithreaded version
class Foo {
private Helper helper = null;
public synchronized Helper getHelper() {
if (helper == null)
helper = new Helper();
return helper;
}
// other functions and members...
}

The code above performs synchronization every time getHelper() is called. The double-checked locking idiom tries to avoid synchronization after the helper is allocated:

// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null)
synchronized(this) {
if (helper == null)
helper = new Helper();
}
return helper;
}
// other functions and members...
}

Unfortunately, that code just does not work in the presence of either optimizing compilers or shared memory multiprocessors.

It doesn't work

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.

Lots of very smart people have spent lots of time looking at this. There is no way to make it work without requiring each thread that accesses the helper object to perform synchronization.

The first reason it doesn't work

The most obvious reason it doesn't work it that the writes that initialize the Helper object and the write to the helper 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.

If the compiler inlines the call to the constructor, then the writes that initialize the object and the write to the helper field can be freely reordered if the compiler can prove that the constructor cannot throw an exception or perform synchronization.

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.

Doug Lea has written a more detailed description of compiler-based reorderings.

A test case showing that it doesn't work

Paul Jakubik found an example of a use of double-checked locking that did not work correctly. A slightly cleaned up version of that code is available here.

When run on a system using the Symantec JIT, it doesn't work. In particular, the Symantec JIT compiles

singletons[i].reference = new Singleton();

to the following (note that the Symantec JIT using a handle-based object allocation system).

0206106A   mov         eax,0F97E78h
0206106F call 01F6B210 ; allocate space for
; Singleton, return result in eax
02061074 mov dword ptr [ebp],eax ; EBP is &singletons[i].reference
; store the unconstructed object here.
02061077 mov ecx,dword ptr [eax] ; dereference the handle to
; get the raw pointer
02061079 mov dword ptr [ecx],100h ; Next 4 lines are
0206107F mov dword ptr [ecx+4],200h ; Singleton's inlined constructor
02061086 mov dword ptr [ecx+8],400h
0206108D mov dword ptr [ecx+0Ch],0F84030h

As you can see, the assignment to singletons[i].reference 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).

A fix that doesn't work

Given the explanation above, a number of people have suggested the following code:

// (Still) Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) {
Helper h;
synchronized(this) {
h = helper;
if (h == null)
synchronized (this) {
h = new Helper();
} // release inner synchronization lock
helper = h;
}
}
return helper;
}
// other functions and members...
}

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 Helper object and the assignment to the field helper.

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 helper = h; 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.

More fixes that don't work

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, Do not use it.

However , even with a full memory barrier being performed by the thread that initializes the helper object, it still doesn't work.

The problem is that on some systems, the thread which sees a non-null value for the helper field also needs to perform memory barriers.

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.

I've created a separate web page with a discussion of how this can actually happen on an Alpha processor.

Is it worth the trouble?

For most applications, the cost of simply making the getHelper() 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.

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.

Making it work for static singletons

If the singleton you are creating is static (i.e., there will only be one Helper created), as opposed to a property of another object (e.g., there will be one Helper for each Foo object, there is a simple and elegant solution.

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.

class HelperSingleton {
static Helper singleton = new Helper();
}

It will work for 32-bit primitive values

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.

// Correct Double-Checked Locking for 32-bit primitives
class Foo {
private int cachedHashCode = 0;
public int hashCode() {
int h = cachedHashCode;
if (h == 0)
synchronized(this) {
if (cachedHashCode != 0) return cachedHashCode;
h = computeHashCode();
cachedHashCode = h;
}
return h;
}
// other functions and members...
}

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.

// Lazy initialization 32-bit primitives
// Thread-safe if computeHashCode is idempotent
class Foo {
private int cachedHashCode = 0;
public int hashCode() {
int h = cachedHashCode;
if (h == 0) {
h = computeHashCode();
cachedHashCode = h;
}
return h;
}
// other functions and members...
}

Making it work with explicit memory barriers

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:

// C++ implementation with explicit memory barriers
// Should work on any platform, including DEC Alphas
// From "Patterns for Concurrent and Distributed Objects",
// by Doug Schmidt
template <class TYPE, class LOCK> TYPE *
Singleton<TYPE, LOCK>::instance (void) {
// First check
TYPE* tmp = instance_;
// Insert the CPU-specific memory barrier instruction
// to synchronize the cache lines on multi-processor.
asm ("memoryBarrier");
if (tmp == 0) {
// Ensure serialization (guard
// constructor acquires lock_).
Guard<LOCK> guard (lock_);
// Double check.
tmp = instance_;
if (tmp == 0) {
tmp = new TYPE;
// Insert the CPU-specific memory barrier instruction
// to synchronize the cache lines on multi-processor.
asm ("memoryBarrier");
instance_ = tmp;
}
return tmp;
}

Fixing Double-Checked Locking using Thread Local Storage

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.
  class Foo {
/** If perThreadInstance.get() returns a non-null value, this thread
has done synchronization needed to see initialization
of helper */
private final ThreadLocal perThreadInstance = new ThreadLocal();
private Helper helper = null;
public Helper getHelper() {
if (perThreadInstance.get() == null) createHelper();
return helper;
}
private final void createHelper() {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
// Any non-null value would do as the argument here
perThreadInstance.set(perThreadInstance);
}
}

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. Doug Lea analyzed the performance of some techniques for implementing lazy initialization.

Under the new Java Memory Model

As of JDK5, there is a new Java Memory Model and Thread specification.

Fixing Double-Checked Locking using Volatile

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 this entry in Jeremy Manson's blog for more details.

With this change, the Double-Checked Locking idiom can be made to work by declaring the helper field to be volatile. This does not work under JDK4 and earlier.

// Works with acquire/release semantics for volatile
// Broken under current semantics for volatile
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}

Double-Checked Locking Immutable Objects

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.

Descriptions of double-check idiom




micheal's tech 2008-10-23 14:25 发表评论
]]>
设计模式解析之——AbstractFactory模式http://www.shnenglu.com/michaelgao/archive/2008/10/22/64685.htmlmicheal's techmicheal's techWed, 22 Oct 2008 02:44:00 GMThttp://www.shnenglu.com/michaelgao/archive/2008/10/22/64685.htmlhttp://www.shnenglu.com/michaelgao/comments/64685.htmlhttp://www.shnenglu.com/michaelgao/archive/2008/10/22/64685.html#Feedback0http://www.shnenglu.com/michaelgao/comments/commentRss/64685.htmlhttp://www.shnenglu.com/michaelgao/services/trackbacks/64685.html

0 引言

0.1 目的

       本文档给计模式之——AbstractFactory模式的简化诠释,q给出其C++实现?/p>

0.2 说明

Project

Design Pattern ExplanationQBy K_EckelQ?/p>

Authorization

Free Distributed but Ownership Reserved

Date

Test Bed

MS Visual C++ 6.0

0.3 参?/font>

       在本文档的写作中Q参考了以下的资源,在此列出表示感谢Q?/p>

u       书籍

[GoF 2000]QGoF,Design Patterns-Elements of Reusable Object-Oriented Software

Addison-Wesley 2000/9.

        [Martine 2003]QRobert C.Martine, Agile Software Development Principles, Patterns, and Practices, Pearson Education, 2003.

0.4 联系作?/font>

Author

K_Eckel

State

Candidate for Master’s Degree School of

E_mail

frwei@whu.edu.cn  

2 AbstractFactory模式

2.1 问题

       假设我们要开发一ƾ游戏,当然Z吸引更多的h玩,游戏隑ֺ不能太大Q让大家都没有信心了Q估计游戏也没有前途了Q,但是也不能太单(没有挑战性也不符合玩家的心理Q。于是我们就可以采用q样一U处理策略:为游戏设立等U,初、中U、高U甚xBTU。假设也是过关的游戏Q每个关卡都有一些怪物QmonsterQ守着Q玩家要把这些? 物干掉才可以q关。作为开发者,我们׃得不创徏怪物的类Q然后初U怪物、中U怪物{都l承自怪物c(当然不同U类的则需要另创徏c,但是模式相同Q。在 每个兛_Q我们都要创建怪物的实例,例如初񔞮创建初U怪物Q有很多U类Q、中U创ZU怪物{。可以想象在q个pȝ中,会有成千上万的怪物实例要创 建,问题是还要保证创建的时候不会出错:初不能创徏BTU的怪物Q玩家就郁闷了,玩家一郁闷Q游戏也挂挂了Q,反之也不可以?/p>

       AbstractFactory模式是用来解决q类问题的:要创Zl相x者相互依赖的对象?/p>

2.2 模式选择

       AbstractFactory模式典型的结构图为:


?font face="Times New Roman">2-1
Q?font face="Times New Roman">AbstractFactoryPattern
l构?/p>

       AbstractFactory模式关键是这一l对象的创徏装C个用于创建对象的c(ConcreteFactoryQ中Q维护这样一个创建类Ll护n多相兛_象的创徏q程要简单的多?/p>

2.3 实现

       AbstractFactory模式的实现比较简单,q里Z方便初学者的学习和参考,给出完整的实现代码Q所有代码采?font face="Times New Roman">C++实现Qƈ?font face="Times New Roman">VC 6.0下测试运行)?br>

代码片断1Q?/font>Product.h
//Product.h

#ifndef _PRODUCT_H_
#define _PRODUCT_H_

class AbstractProductA
{
public:
 virtual ~AbstractProductA();

protected:
 AbstractProductA();

private:

};

class AbstractProductB
{
public:
 virtual ~AbstractProductB();

protected:
 AbstractProductB();

private:

};

class ProductA1:public AbstractProductA
{
public:
 ProductA1();

 ~ProductA1();

protected:

private:

};

class ProductA2:public AbstractProductA
{
public:
 ProductA2();

 ~ProductA2();

protected:

private:

};

class ProductB1:public AbstractProductB
{
public:
 ProductB1();

 ~ProductB1();

protected:

private:

};

class ProductB2:public AbstractProductB
{
public:
 ProductB2();

 ~ProductB2();

protected:

private:

};

#endif //~_PRODUCT_H_

代码片断2Q?/font>Product.cpp
//Product.cpp

#include "Product.h"

#include <iostream>
using namespace std;

AbstractProductA::AbstractProductA()
{

}

AbstractProductA::~AbstractProductA()
{

}

AbstractProductB::AbstractProductB()
{

}

AbstractProductB::~AbstractProductB()
{

}

ProductA1::ProductA1()
{
 cout<<"ProductA1..."<<endl;
}

ProductA1::~ProductA1()
{

}

ProductA2::ProductA2()
{
 cout<<"ProductA2..."<<endl;
}

ProductA2::~ProductA2()
{

}

ProductB1::ProductB1()
{
 cout<<"ProductB1..."<<endl;
}

ProductB1::~ProductB1()
{

}

ProductB2::ProductB2()
{
 cout<<"ProductB2..."<<endl;
}

ProductB2::~ProductB2()
{

}

代码片断3Q?/font>AbstractFactory.h
//AbstractFactory.h

#ifndef _ABSTRACTFACTORY_H_
#define _ABSTRACTFACTORY_H_

class AbstractProductA;
class AbstractProductB;

class AbstractFactory
{
public:
 virtual ~AbstractFactory();

 virtual AbstractProductA* CreateProductA() = 0;

 virtual AbstractProductB* CreateProductB() = 0;

protected:
 AbstractFactory();

private:

};

class ConcreteFactory1:public AbstractFactory
{
public:
 ConcreteFactory1();

 ~ConcreteFactory1();

 AbstractProductA* CreateProductA();

 AbstractProductB* CreateProductB();

protected:

private:

};

class ConcreteFactory2:public AbstractFactory
{
public:
 ConcreteFactory2();

 ~ConcreteFactory2();

 AbstractProductA* CreateProductA();

 AbstractProductB* CreateProductB();

protected:

private:

};
#endif //~_ABSTRACTFACTORY_H_

代码片断4Q?/font>AbstractFactory.cpp
//AbstractFactory.cpp

#include "AbstractFactory.h"
#include "Product.h"

#include <iostream>
using namespace std;

AbstractFactory::AbstractFactory()
{

}

AbstractFactory::~AbstractFactory()
{

}

ConcreteFactory1::ConcreteFactory1()
{

}

ConcreteFactory1::~ConcreteFactory1()
{

}

AbstractProductA* ConcreteFactory1::CreateProductA()
{
 return new ProductA1();
}

AbstractProductB* ConcreteFactory1::CreateProductB()
{
 return new ProductB1();
}

ConcreteFactory2::ConcreteFactory2()
{

}

ConcreteFactory2::~ConcreteFactory2()
{

}

AbstractProductA* ConcreteFactory2::CreateProductA()
{
 return new ProductA2();
}

AbstractProductB* ConcreteFactory2::CreateProductB()
{
 return new ProductB2();
}

代码片断5Q?/font>main.cpp
//main.cpp

#include "AbstractFactory.h"

#include <iostream>
using namespace std;

int main(int argc,char* argv[])
{
 AbstractFactory* cf1 = new ConcreteFactory1();

 cf1->CreateProductA();
 cf1->CreateProductB();

 AbstractFactory* cf2 = new ConcreteFactory2();
 cf2->CreateProductA();
 cf2->CreateProductB();

 return 0;
}

       AbstractFactory模式的实C码很单,在测试程序中可以看到Q当我们要创Zl对象(ProductA1QProductA2Q的时候我们只用维护一个创建对象(ConcreteFactory1Q,大大化了l护的成本和工作?/font>

2.4 讨论

       AbstractFactory模式和Factory模式的区别是初学Q用)设计模式时候的一个容易引起困惑的地方。实际上QAbstractFactory模式是ؓ创徏一l(有多c)相关或依赖的对象提供创徏接口Q而Factory模式正如我在相应的文档中分析的是?strong>一c?/strong>对象提供创徏接口或gq对象的创徏到子cM实现。ƈ且可以看刎ͼAbstractFactory模式通常都是使用Factory模式实现QConcreteFactory1Q?/font>




micheal's tech 2008-10-22 10:44 发表评论
]]>
~辑decorateE序旉C个问?/title><link>http://www.shnenglu.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.shnenglu.com/michaelgao/archive/2008/10/16/64170.html</guid><wfw:comment>http://www.shnenglu.com/michaelgao/comments/64170.html</wfw:comment><comments>http://www.shnenglu.com/michaelgao/archive/2008/10/16/64170.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/michaelgao/comments/commentRss/64170.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/michaelgao/services/trackbacks/64170.html</trackback:ping><description><![CDATA[class Decorator:public Beverage<br>{<br>    public:<br>        Decorator(Beverage * com);<br>        virtual ~Decorator();<br>        virtual string get_descrption();<br>   <span style="background-color: yellow;"> protected:</span><br>      <span style="background-color: yellow;">  Beverage * component;</span><br><br><br>};<br><br> 而MilkDecoratorl承了Decorator,如果component 为私有的则MilkDecorator便不能访问?br><br>如果milkDecorator 设计成这样就不会q反了封装的原则?br>基本上只有一个区别,是protect成员能被zc访问!而派生类对private没有Ҏ讉K权! <br><br><img src ="http://www.shnenglu.com/michaelgao/aggbug/64170.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/michaelgao/" target="_blank">micheal's tech</a> 2008-10-16 17:04 <a href="http://www.shnenglu.com/michaelgao/archive/2008/10/16/64170.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UML中一些符L意义http://www.shnenglu.com/michaelgao/archive/2008/10/13/63889.htmlmicheal's techmicheal's techMon, 13 Oct 2008 06:53:00 GMThttp://www.shnenglu.com/michaelgao/archive/2008/10/13/63889.htmlhttp://www.shnenglu.com/michaelgao/comments/63889.htmlhttp://www.shnenglu.com/michaelgao/archive/2008/10/13/63889.html#Feedback0http://www.shnenglu.com/michaelgao/comments/commentRss/63889.htmlhttp://www.shnenglu.com/michaelgao/services/trackbacks/63889.htmlhttp://book.csdn.net/bookfiles/575/10057518902.shtml

虚线头表示“依赖关系”Q依赖有“使用”的语义,比如患者与ȝ的关pR?br>实线头表示“带了D行的兌关系”Q从一个类到另一cR?br>使用实线头旉常会带?#8220;多重?#8221;的表达方式。如Q一对多Q一对一Q多对多{等

常见的关pLQ一般化关系QGeneralizationQ,兌关系QAssociationQ,聚合关系QAggregationQ,合成关系QCompositionQ,依赖关系QDependencyQ?/font>

      其中Q聚合关p(AggregationQ,合成关系QCompositionQ属于关联关p(AssociationQ?/font>

      一般关p表Cؓl承或实现关p?is a)Q关联关p表Cؓ变量(has a )Q依赖关p表Cؓ函数中的参数(use a)?/font>

      一般化关系Q表CZؓcMcM间的l承关系Q接口与接口之间的承,cd接口的实现关pR?br>      表示ҎQ?用一个空心箭_实线Q箭头指向父cR或I心头Q虚U,如果父类是接口?/font>

      兌关系Q类与类之间的联接,它一个类知道另一个类的属性和Ҏ?br>      表示ҎQ用 实线Q箭_ 头指向被用的cR?/font>

      聚合关系Q是兌关系的一U,是强的关联关pR聚合关pL整体和个体的关系。关联关pȝ两个cd于同一层次上,啊聚合关pM个类处于不同的层ơ,一个是整体Q一个是部分?br>      表示ҎQ空心菱形+实线Q箭_头指向部分?/font>

      合成关系Q是兌关系的一U,是比聚合关系强的关系。它要求普通的聚合关系中代表整体的对象负责代表部分的对象的生命周期Q合成关pM能共享?br>      表示ҎQ实心菱形+实线Q箭_

      依赖关系Q是cMcM间的q接Q表CZ个类依赖于另一个类的定义。例如如果A依赖于BQ则B体现为局部变量,Ҏ的参数、或静态方法的调用?br>      表示ҎQ虚U+头


图一:

uploads/200706/04_211918_1121523.jpg


此实U箭头表C? l承, 从一个非接口cȝl承.

图二:
uploads/200706/04_212112_1121525gl.jpg


那条q线表示双向兌:
看左? Flight扮演assignedFights角色, ??个Plane跟他兌(一个航班要么取消了没有飞机,要么只能对应一枉?
看右? Plane扮演着assignedPlane角色, ?到多个Flight跟他兌(一个飞机可以参与多个航? 也可以停在仓库里面烂?

图三:
uploads/200706/04_213002_1121526dxgl.jpg


那条q线表示单向兌:
基本的意义跟上面的是一L, 唯一不同的是, 双的类对左边的cL一无所知的.

囑֛:
uploads/200706/04_213232_1121527rjb.jpg


那个大的包围的框叫Y件包, 名字为Account, ׃些可以归cȝcd装v?

图五:
uploads/200706/04_213441_1121529xjc.gif


如此虚线的箭头表C实C个接?

囑օ:
uploads/200706/04_213626_11215210gll.jpg


水^的连U还是表CZ面所说的兌, 但从兌q线中引伸出来的虚线, q意呛_Flightcȝ一个实例关联到 FrequentFlyer cȝ一个实例时Q将会?MileageCredit cȝ一个实?

图七:
uploads/200706/04_213911_11215211jbjh.jpg


带菱形的头表示基本聚合, ׃囄? WheelcL演wheels角色, 聚合4个到Car对象里面?
I心的菱形表CWheel对象q不随Car的创创?销毁而销?

囑օ:
uploads/200706/04_214248_11215212zhjh.jpg


意义和上面类? 唯一不同的是, 实心菱Ş表示Department对象随Company对象的创创?销毁而销?

图九:
uploads/200706/04_214435_11215213fs.gif


表示反射兌, 昄一个Employeecd何通过manager / manages角色与它本n相关。当一个类兌到它本nӞqƈ不意味着cȝ实例与它本n相关Q而是cȝ一个实例与cȝ另一个实例相兟?br>


micheal's tech 2008-10-13 14:53 发表评论
]]>
设计模式解析之——Observer模式Qk_eckel转自微Y高校博客K_eckel's mindviewQ?http://www.shnenglu.com/michaelgao/archive/2008/10/10/63633.htmlmicheal's techmicheal's techFri, 10 Oct 2008 03:04:00 GMThttp://www.shnenglu.com/michaelgao/archive/2008/10/10/63633.htmlhttp://www.shnenglu.com/michaelgao/comments/63633.htmlhttp://www.shnenglu.com/michaelgao/archive/2008/10/10/63633.html#Feedback0http://www.shnenglu.com/michaelgao/comments/commentRss/63633.htmlhttp://www.shnenglu.com/michaelgao/services/trackbacks/63633.html

0 引言

0.1 目的

       本文档给计模式之——Observer模式的简化诠释,q给出其C++实现?/p>

0.2 说明

Project

Design Pattern ExplanationQBy K_EckelQ?/p>

Authorization

Free Distributed but Ownership Reserved

Date

Test Bed

MS Visual C++ 6.0

0.3 参?/font>

       在本文档的写作中Q参考了以下的资源,在此列出表示感谢Q?/p>

u       书籍

[GoF 2000]QGoF,Design Patterns-Elements of Reusable Object-Oriented Software

Addison-Wesley 2000/9.

        [Martine 2003]QRobert C.Martine, Agile Software Development Principles, Patterns, and Practices, Pearson Education, 2003.

0.4 联系作?/font>

Author

K_Eckel

State

Candidate for Master’s Degree School of

E_mail

frwei@whu.edu.cn  

2 Observer模式

2.1 问题

       Observer模式应该可以说是应用最多、媄响最q的模式之一Q因为Observer的一个实例Model/View/ControlQMVCQ结构在pȝ开发架构设计中有着很重要的C和意义,MVC实现了业务逻辑和表C层的解耦?strong>个h也认?/strong>Observer模式是Y件开发过E中必须要掌握和使用的模式之一。在MFC中,Doc/ViewQ文档视囄构)提供了实现MVC的框架结构(有一个从设计模式QObserver模式Q的角度分析分析Doc/View的文章正在进一步的撰写当中Q遗憄是时_Q)。在Java阵容中,Struts则提供和MFC中Doc/Viewl构cM的实现MVC的框架。另外Java语言本n提供了Observer模式的实现接口,q将在讨Zl出?/p>

       当然QMVC只是Observer模式的一个实例。Observer模式要解决的问题为:建立一个一QSubjectQ对多(ObserverQ? 的依赖关p,q且做到?#8220;一”变化的时候,依赖q个“一”的多也能够同步改变。最常见的一个例子就是:对同一l数据进行统计分析时候,我们希望能够提供? UŞ式的表示Q例如以表格q行l计昄、柱状图l计昄、百分比l计昄{)。这些表C都依赖于同一l数据,我们当然需要当数据改变的时候,所有的l计? 昄都能够同时改变。Observer模式是解决了这一个问题?/p>

2.2 模式选择

       Observer模式典型的结构图为:


?font face="Times New Roman">2-1
Q?font face="Times New Roman">Observer Pattern
l构?/p>

       q里的目?font face="Times New Roman">Subject提供依赖于它的观察?font face="Times New Roman">Observer的注册(AttachQ和注销Q?font face="Times New Roman">DetachQ操作,q且提供了得依赖于它的所有观察者同步的操作Q?font face="Times New Roman">NotifyQ。观察?font face="Times New Roman">Observer则提供一?font face="Times New Roman">Update操作Q注意这里的Observer?font face="Times New Roman">Update操作q不?font face="Times New Roman">Observer改变?font face="Times New Roman">Subject目标状态的时候就对自p行更斎ͼq个更新操作要gq到Subject对象发出Notify通知所?font face="Times New Roman">Observerq行修改Q调?font face="Times New Roman">UpdateQ?/p>

2.3 实现

       Observer模式的实现有些特点,q里Z方便初学者的学习和参考,给出完整的实现代码Q所有代码采?font face="Times New Roman">C++实现Qƈ?font face="Times New Roman">VC 6.0下测试运行)?br>

代码片断1Q?/font>Subject.h
//Subject.h

#ifndef _SUBJECT_H_
#define _SUBJECT_H_

#include <list>
#include <string>
using namespace std;

typedef string State;

class Observer;

class Subject
{
public:
 virtual ~Subject();

 virtual void Attach(Observer* obv);

 virtual void Detach(Observer* obv);

 virtual void Notify();

 virtual void SetState(const State& st) = 0;

 virtual State GetState() = 0;

protected:
 Subject();

private:
 list<Observer* >* _obvs;

};

class ConcreteSubject:public Subject
{
public:
 ConcreteSubject();

 ~ConcreteSubject();

 State GetState();

 void SetState(const State& st);

protected:

private:
 State _st;

};

#endif //~_SUBJECT_H_

代码片断2Q?/font>Subject.cpp
//Subject.cpp

#include "Subject.h"
#include "Observer.h"

#include <iostream>
#include <list>
using namespace std;

typedef string state;

Subject::Subject()
{
 //****在模板的使用之前一定要newQ创?/font>
 _obvs = new list<Observer*>;

}

Subject::~Subject()
{
 
}

void Subject::Attach(Observer* obv)
{
 
 _obvs->push_front(obv);
}

void Subject::Detach(Observer* obv)
{
 if (obv != NULL)
  _obvs->remove(obv);
}

void Subject::Notify()
{
 
 list<Observer*>::iterator it;

 it = _obvs->begin();

 for (;it != _obvs->end();it++)
 {
  //关于模板?/font>iterator的用?/font>

  (*it)->Update(this);
 }
}

ConcreteSubject::ConcreteSubject()
{
 _st = '\0';
}

ConcreteSubject::~ConcreteSubject()
{
 
}


State ConcreteSubject::GetState()
{
 return _st;
}

void ConcreteSubject::SetState(const State& st)
{
 _st = st;
}

代码片断3Q?/font>Observer.h
//Observer.h

#ifndef _OBSERVER_H_
#define _OBSERVER_H_

#include "Subject.h"

#include <string>
using namespace std;

typedef string State;

class Observer
{
public:
 virtual ~Observer();

 virtual void Update(Subject* sub) = 0;

 virtual void PrintInfo() = 0;

protected:
 Observer();

 State _st;

private:

};

class ConcreteObserverA:public Observer
{
public:
 virtual Subject* GetSubject();
 
 ConcreteObserverA(Subject* sub);

 virtual ~ConcreteObserverA();

 //传入Subject作ؓ参数Q这样可以让一?/font>View属于多个?/font>Subject?/font>
 void  Update(Subject* sub);

 void PrintInfo();

protected:

private:
 Subject* _sub;

};

class ConcreteObserverB:public Observer
{
public:
 virtual Subject* GetSubject();
 
 ConcreteObserverB(Subject* sub);

 virtual ~ConcreteObserverB();

 //传入Subject作ؓ参数Q这样可以让一?/font>View属于多个?/font>Subject?/font>
 void  Update(Subject* sub);

 void PrintInfo();

protected:

private:
 Subject* _sub;

};

#endif //~_OBSERVER_H_

代码片断4Q?/font>Observer.cpp
//Observer.cpp

#include "Observer.h"
#include "Subject.h"

#include <iostream>
#include <string>
using namespace std;

Observer::Observer()
{
 _st = '\0';

}

Observer::~Observer()
{

}


ConcreteObserverA::ConcreteObserverA(Subject* sub)
{
 _sub = sub;

 _sub->Attach(this);
}

ConcreteObserverA::~ConcreteObserverA()
{
 _sub->Detach(this);

 if (_sub != 0)
 {
  delete _sub;
 }
}

Subject* ConcreteObserverA::GetSubject()

 return _sub;
}

void ConcreteObserverA::PrintInfo()
{
 cout<<"ConcreteObserverA observer.... "<<_sub->GetState()<<endl;
}

void ConcreteObserverA::Update(Subject* sub)
{
 _st = sub->GetState();

 PrintInfo();
}

ConcreteObserverB::ConcreteObserverB(Subject* sub)
{
 _sub = sub;

 _sub->Attach(this);
}

ConcreteObserverB::~ConcreteObserverB()
{
 _sub->Detach(this);

 if (_sub != 0)
 {
  delete _sub;
 }
}

Subject* ConcreteObserverB::GetSubject()

 return _sub;
}

void ConcreteObserverB::PrintInfo()
{
 cout<<"ConcreteObserverB observer.... "<<_sub->GetState()<<endl;
}

void ConcreteObserverB::Update(Subject* sub)
{
 _st = sub->GetState();

 PrintInfo();
}

代码片断5Q?/font>main.cpp
//main.cpp

#include "Subject.h"
#include "Observer.h"

#include <iostream>
using namespace std;

int main(int argc,char* argv[])
{
 ConcreteSubject* sub = new ConcreteSubject();

 Observer* o1 = new ConcreteObserverA(sub);

 Observer* o2 = new ConcreteObserverB(sub);

 sub->SetState("old");

 sub->Notify();

 sub->SetState("new"); //也可以由Observer调用

 sub->Notify();

 return 0;
}

在Observer模式的实CQSubjectl护一个list作ؓ存储其所有观察者的容器。每当调用Notify操作遍历list中的Observer对象Qƈq播通知改变状态(调用Observer的Update操作Q。目标的状态state可以由Subject自己改变Q示例)Q也可以由Observer的某个操作引起state的改变(可调用Subject的SetState操作Q。Notify操作可以由Subject目标dq播Q示例)Q也可以由Observer观察者来调用Q因为Observerl护一个指向Subject的指针)?/font>

       q行CZE序Q可以看到当Subject处于状?#8220;old”时候,依赖于它的两个观察者都昄“old”Q当目标状态改变ؓ“new”的时候,依赖于它的两个观察者也都改变ؓ“new”?/font>

2.4 讨论

       Observer是媄响极为深q的模式之一Q也是在大型pȝ开发过E中要用到的模式之一。除了MFC、Struts提供了MVC的实现框Ӟ在Java语言中还提供了专门的接口实现Observer模式Q通过专门的类Observable及Observer接口来实现MVC~程模式Q其UML囑֏以表CZؓQ?/font>

 


Java中实现MVC的UML图?/font>

q里的Observer是观察者,Observable则充当目标Subject的角艌Ӏ?/font>

       Observer模式也称为发布-订阅Qpublish-subscribeQ,目标是通知的发布者,观察者则是通知的订阅者(接受通知Q?/font>




micheal's tech 2008-10-10 11:04 发表评论
]]>
C++中接口与实现的分d柄类http://www.shnenglu.com/michaelgao/archive/2008/10/07/63401.htmlmicheal's techmicheal's techTue, 07 Oct 2008 08:13:00 GMThttp://www.shnenglu.com/michaelgao/archive/2008/10/07/63401.htmlhttp://www.shnenglu.com/michaelgao/comments/63401.htmlhttp://www.shnenglu.com/michaelgao/archive/2008/10/07/63401.html#Feedback0http://www.shnenglu.com/michaelgao/comments/commentRss/63401.htmlhttp://www.shnenglu.com/michaelgao/services/trackbacks/63401.html
句柄cL存储和管理基cL针的一个类
需要句柄类的背景:
1Q在对安全要求很高的领域Q即使核心实现已l封闭在库中不可见,但头文g中变量定义仍可能曝露一些内部信?
2Q在设计初期、实现部分会l常变动Q甚臛_文g中变量定义也需要经常变动,因此在重~译的时候头文g也需要编译,
有时候导致编译时间过ѝ?br> 句柄cd是ؓ了解册c问?
// Handle.h
class Implement; //q里是对真正实现功能的类的声?br>
class ImplementHandle //q是Implementcȝ句柄c?br>{
public:
ImplementHandle():lpImplementInstance(NULL){lpImplementInstance = new Implement;}
~ImplementHandle(){ delete lpImplementInstance ;}
public:
// Interface_FOO() 是句柄类提供的接口,它的真正实现是在Implementc里?而这个仅仅是接口"代理"
RE_TYPE Interface_FOO()
{
return lpImplementInstance->FOO
_
Implementation(); //句柄代理调用实现真正的FOO接口
}
//q有其他的接口也一P均是用句柄类代理接口
//....
private:
Implement * lpImplementInstance; //q个是句柄类唯一的数据成?当然Qƈ不一?,可以被句柄类很好地自动管?br>};




  被封装在句柄c里面的真正实现Qclass ImplementQ将与用户隔d来,是_q以后Implement cȝ实现有所改变Q?br>只要它提供的接口不变Q那么它的句柄类׃会改变,而包含句柄类的用P也不用做M相应的改变(所有包?“Handle.h”的模块甚至不用从新编译就可以正常更新x新的Implement实现Q?br>
例如
#include "Handle.h"
Imlementhandle testhandle;
testhandle->Interface_Foo();//调用接口卛_?br> 如果改动了ImplentcȝҎ

  于此相反Q如果直接用class Implement 的定义,那么只要Implementcȝ定义有所改变Q不是public q是private 成员
的更斎ͼQ那么所有包含它的头文g的模块都要从新编译一ơ?br>
q其实就是接口与实现的分,




micheal's tech 2008-10-07 16:13 发表评论
]]>
C++实现设计模式中的Interface from goolgehttp://www.shnenglu.com/michaelgao/archive/2008/10/07/63392.htmlmicheal's techmicheal's techTue, 07 Oct 2008 06:39:00 GMThttp://www.shnenglu.com/michaelgao/archive/2008/10/07/63392.htmlhttp://www.shnenglu.com/michaelgao/comments/63392.htmlhttp://www.shnenglu.com/michaelgao/archive/2008/10/07/63392.html#Feedback0http://www.shnenglu.com/michaelgao/comments/commentRss/63392.htmlhttp://www.shnenglu.com/michaelgao/services/trackbacks/63392.htmlInterface suffix.
link

Definition:

A class is a pure interface if it meets the following requirements:

  • It has only public pure virtual ("= 0") methods and static methods (but see below for destructor).
  • It may not have non-static data members.
  • It need not have any constructors defined. If a constructor is provided, it must take no arguments and it must be protected.
  • If it is a subclass, it may only be derived from classes that satisfy these conditions and are tagged with the Interface suffix.

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, The C++ Programming Language, 3rd edition, section 12.4 for details.

Pros: Tagging a class with the Interface suffix lets others know that they must not add implemented methods or non static data members. This is particularly important in the case of multiple inheritance. Additionally, the interface concept is already well-understood by Java programmers.

Cons: The Interface 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.

Decision: A class may end with Interface 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 Interface.




micheal's tech 2008-10-07 14:39 发表评论
]]>
ƷŷƬþùŷ...| ۺһ˾þþƷ| պƷþþþþ| þþƷ| ˺ݺۺϾþ| þþþۺĻ| vavavaþ| ƷþþþӰԺɫ| þþþ޾Ʒַ | þþþƷþþþɫӰ| þҹɫ˾ƷС˵| þþ뾫ƷպĦ| Բľþþþþ| ɫۺϾþ| þĻƷһ| 99þɫĻ| þˮav뾫Ʒ鶹| þþþþҹƷ| þɫۺҹž| þþþþëƬѿ| 91Ըߺþþþ| Ʒvaþþþþþ| Ʒþۺ123| Ʒ99þaaaһëƬ| ŮƷþþ| þñۺϾþ| þþþAVۺϲҰ| ԭۺϾþô˵| AVһþ| 7777þþùƷ| þþþѿӰƬ| ƷþþĻ| ҹҹݺݾþö| 777þµַ| ھƷþþþӰԺվ| ͵ٸþþþþþþ| 77777ҹþö| þþþþùaѹۿɫƬ| 뾫Ʒþþþ.. | 69Ʒþþþ99| þ|