2014年4月21日

  这个知识点之前还真的没听说过,这也看别人博客看到的,转过来一下加深一下印象。

序列点

那么,所谓的序列点是什么意思呢?

序列点是一个时间点(在整个表达式全部计算完毕之后或在 ||、 &&、 ? : 或逗号 运算符处, 或在函数调用之前), 此刻尘埃落定,所有的副作用都已确保结束。 ANSI/ISO C 标准这样描述:
在上一个和下一个序列点之间,一个对象所保存的值至多只能被表达式的计算修改一次。而且前一个值只能用于决定将要保存的值。

第二句话比较费解。它说在一个表达式中如果某个对象需要写入, 则在同一表达式中对该对象的访问应该只局限于直接用于计算将要写入的值。这条规则有效地限制了只有能确保在修改之前才访问变量的表达式为合法。

例如 i = i+1 合法,而 a[i] = i++ 则非法。为什么这样的代码:a[i] = i++; 不能工作?子表达式 i++ 有一个副作用 --- 它会改变 i 的值 --- 由于 i 在同一表达式的其它地方被引用,这会导致无定义的结果,无从判断该引用(左边的 a[i] 中)是旧值还是新值。那么,对于 a[i] = i++; 我们不知道 a[] 的哪一个分量会被改写,但 i 的确会增加 1,对吗?
不一定!如果一个表达式和程序变得未定义,则它的所有方面都会变成未定义。

为什么&& 和 || 运算符可以产生序列点呢?这些运算符在此处有一个特殊的例外:如果左边的子表达式决定最终结果 (即,真对于 || 和假对于 && ) ,则右边的子表达式不会计算。因此,从左至右的计算可以确保,对逗号表达式也是如此。而且,所有这些运算符 (包括 ? : ) 都会引入一个额外的内部序列点。

来看看下面的代码:

int i=7; printf("%d\n", i++ * i++);

你认为会返回什么?56?no。正确答案是返回 49?很多人会问为什么?难道不该打印出56吗?在ccfaq中有非常详尽的解释,根本原因在于c中的序列点。

请 注意,尽管后缀自加和后缀自减操作符 ++ 和 -- 在输出其旧值之后才会执行运算,但这里的“之后”常常被误解。没有任何保证确保自增或自减会在输出变量原值之后和对表达式的其它部分进行计算之前立即进 行。也不能保证变量的更新会在表达式 “完成” (按照 ANSI C 的术语, 在下一个"序列点"之前) 之前的某个时刻进行。本例中, 编译器选择使用变量的旧值相乘以后再对二者进行自增运算。只有到达一个序列点之后,自增运算才能保证真正被执行。

包含多个不确定的副作用 的代码的行为总是被认为未定义。(简单而言, “多个不确定副作用”是指在同一个表达式中使用导致同一对象修改两次或修改以后又被引用的自增,自减和赋值操作符的任何组合。这是一个粗略的定义。) 甚至都不要试图探究这些东西在你的编译器中是如何实现的 (这与许多 C 教科书上的弱智练习正好相反);正如 K&R 明智地指出,"如果你不知道它们在不同的机器上如何实现, 这样的无知可能恰恰会有助于保护你"。
---------------------------------------------------------------------------------------------------------------------------------------------
C 语言中,术语副作用(side effect)是指对数据对象或者文件的修改。例如,以下语句

        var = 99;

的副作用是把 var 的值修改成 99。对表达式求值也可能产生副作用,例如:

        se = 100

对这个表达式求值所产生的副作用就是 se 的值被修改成 100。

    序列点(sequence point)是指程序运行中的一个特殊的时间点,在该点之前的所有副作用已经结束,并且后续的副作用还没发生。

    C 语句结束标志——分号(;)是序列点。也就是说,C 语句中由赋值、自增或者自减等引起的副作用在分号之前必须结束。我们以后会说到一些包含序列点的运算符。任何完整表达式(full expression)运算结束的那个时间点也是序列点。所谓完整表达式,就是说这个表达式不是子表达式。而所谓的子表达式,则是指表达式中的表达式。例如:

        f = ++e % 3

这整个表达式就是一个完整表达式。这个表达式中的 ++e、3 和 ++e % 3 都是它的子表达式。

    有了序列点的概念,我们下面来分析一下一个很常见的错误:

        int x = 1, y;
        y = x++ + x++;

这里 y = x++ + x++ 是完整表达式,而 x++ 是它的子表达式。这个完整表达式运算结束的那一点是一个序列点,int x = 1, y; 中的 ; 也是一个序列点。也就是说,x++ + x++ 位于两个序列点之间。标准规定,在两个序列点之间,一个对象所保存的值最多只能被修改一次。但是我们清楚可以看到,上面这个例子中,x 的值在两个序列点之 间被修改了两次。这显然是错误的!这段代码在不同的编译器上编译可能会导致 y 的值有所不同。比较常见的结果是 y 的值最后被修改为 2 或者 3。在此,我不打算就这个问题作更深入的分析,各位只要记住这是错误的,别这么用就可以了。有兴趣的话,可以看看以下列出的相关资料。

相关资料:
  自增运算符和自减运算符
  让我耿耿于怀的一道笔试题

C 语言标准对副作用和序列点的定义如下:

    Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression may produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.

翻译如下:

    访问易变对象,修改对象或文件,或者调用包含这些操作的函数都是副作用,它们都会改变执行环境的状态。计算表达式也会引起副作用。执行序列中某些特定的点被称为序列点。在序列点上,该点之前所有运算的副作用都应该结束,并且后继运算的副作用还没发生。

参考资料:C Primer 5th Edition
          The C Programming Language 2nd Edition
          C99 标准

分类: C
posted @ 2014-04-21 01:39 柳清风 阅读(210) | 评论 (0)编辑 收藏
由于之前一直在做C++项目,对C语言的了解并不是那么深入,现在开始做C项目,有些知识点还是不够清晰,今天在网上找了static用法,转过来以加深自己的印象。

c语言中static 用法

static在c里面可以用来修饰变量,也可以用来修饰函数。
先看用来修饰变量的时候。变量在c里面可分为存在全局数据区、栈和堆里。其实我们平时所说的堆栈是栈而不是堆,不要弄混。
int a ;
int main()
{
    int b ; 
    int c* = (int *)malloc(sizeof(int));
}
a是全局变量,b是栈变量,c是堆变量。
static对全局变量的修饰,可以认为是限制了只能是本文件引用此变量。有的程序是由好多.c文件构成。彼此可以互相引用变量,但加入static修饰之后,只能被本文件中函数引用此变量。
static对栈变量的修饰,可以认为栈变量的生命周期延长到程序执行结束时。一般来说,栈变量的生命周期由OS管理,在退栈的过程中,栈变量的生命也就结束了。但加入static修饰之后,变量已经不再存储在栈中,而是和全局变量一起存储。同时,离开定义它的函数后不能使用,但如再次调用定义它的函数时,它又可继续使用, 而且保存了前次被调用后留下的值。
static对函数的修饰与对全局变量的修饰相似,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。

文件a.c
static int i; //只在a文件中用
int j;          //在工程里用
static void init()         //只在a文件中用
{
}
void callme()          //在工程中用
{
    static int sum;
}

上面的全局i变量和init()函数只能用在a.c文件中,全局变量sum的作用域只在callme里。变量j和函数callme()的全局限扩充到整个工程文件。所以可以在下面的b.c中用extern关键字调用。extern告诉编译器这个变量或者函数在其他文件里已经被定义了。

文件b.c
extern int j;                    //调用a文件里的
extern void callme();   //调用a文件里的
int main()
{
  ...
}

extern的另外用法是当C和C++混合编程时如果c++调用的是c源文件定义的函数或者变量,那么要加extern来告诉编译器用c方式命名函数:

文件A.cpp调用a.c里面的变量i和函数callme()
extern "C"  //在c++文件里调用c文件中的变量
{
   
int j;
   
void callme();
}
int main()
{
   callme();
}

二 static法则:

A、若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
B、若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
C、设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题;

全局变量有外部、静态两种存储方式。
(1)全局变量一般用外部存储方式存储,用保留字extern加以定义。此时,变量的作用域是构成整个程序的所有程序文件,也就是定义的外部变量可供其它程序文件使用。
使用这样的全局变量一定要非常慎重,一旦产生错误,将波及整个程序。
(2)如果希望全局变量仅限于本程序文件使用,而其它程序文件中不能引用,这时必须将其存储方式定义为静态存储方式,用保留字static加以定义。此时称为静态外部变量。
例如,在上例文件filel.c中,如果作这样的定义:
static int a:
则变量a的作用域被缩小至本程序文件filel.c,文件file2.c中不能引用。
值得注意的是对全局变量加static,定义为静态存储方式,并不意味着是静态存储;而不加static,是动态存储。两种形式的全局变量(外部变量)都是静态存储方式,都是编译时分配存储空间,但作用域不同。使用静态外部变量,有利于隔离错误,有利于模块化程序设计。
(3)全局变量的缺省存储方式是外部存储方式。
前面章节中的程序没有见到变量的存储类别定义,实际上采用变量的缺省存储方式。对局部变量采用auto方式,对全局变量采用extern方式。这也是至今为止,我们在程序中没有见到auto、extern等的原因。
至此,我们对变量的存储类别及数据类型进行了全面讨论,在此作个小结。
1.变量定义的一般形式
存储类别数据类型变量表;
2.变量定义的作用
①规定了变量的取值范围。
②规定了变量进行的运行操作。
③规定了变量的作用域。
④规定了变量的存储方式。
⑤规定了变量占用的存储空间。
3.局部变量和全局变量
从作用域角度将变量分为局部变量和全局变量。它们采取的存储类别如下:
局部变量:
①自动变量,即动态局部变量(离开函数,值就消失)。
②静态局部变量(离开函数,值仍保留)。
③寄存器变量(离开函数,值就消失)。
④形式参数可以定义为自动变量或寄存器变量。
全局变量:
①静态外部变量(只限本程序文件使用)。
②外部变量(即非静态的外部变量,允许其它程序文件引用)。
4.动态存储和静态存储
从变量存在时间可将变量存储分为动态存储和静态存储。静态存储是在整个程序运行时都存在,而动态存储则是在调用函数时临时分配存储单元。
动态存储:
①自动变量(函数内有效)。
②寄存器变量(函数内有效)。
③形式参数。
静态存储:
①静态局部变量(函数内有效)。
②静态外部变量(本程序文件内有效)。
③外部变量(整个程序可引用)。
5.静态存储区和动态存储区
从变量值存放的位置可将变量存储区分为静态存储区和动态存储区:
内存中静态存储区:
①静态局部变量。
②静态外部变量。
③外部变量(可被同一程序其它文件引用)。
内存中动态存储区:自动变量和形式参数。
CPU中的寄存器:寄存器变量。


原文:http://www.cnblogs.com/yezhenhan/archive/2011/10/31/2229724.html

希望大家对于大型C工程的开发及重构能给小弟一些意见和建议。
posted @ 2014-04-21 01:14 柳清风 阅读(250) | 评论 (0)编辑 收藏

2012年1月11日

定义与结构

访问者模式,顾名思义使用了这个模式后就可以在不修改已有程序结构的前提下,通过

添加额外的访问者来完成对已有代码功能的提升。

定义为:表示一个作用于某对象结构中的各元

素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

1) 访问者角色(Visitor):为该对象结构中具体元素角色声明一个访问操作接口。该操作

接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色。这样访问者就可

以通过该元素角色的特定接口直接访问它。

2) 具体访问者角色(Concrete Visitor):实现每个由访问者角色(Visitor)声明的操作。

3) 元素角色(Element):定义一个Accept 操作,它以一个访问者为参数。

4) 具体元素角色(Concrete Element):实现由元素角色提供的Accept 操作。

5) 对象结构角色(Object Structure):这是使用访问者模式必备的角色。它要具备以下特

征:能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是

一个复合(组合模式)或是一个集合,如一个列表或一个无序集合。

class Visitor;

 

class Element

{

public:

     virtual ~Element(){}

 

     virtual void Accept(Visitor &rVisitor) = 0;

 

protected:

     Element(){}

};

 

class ConcreateElementA

     : public Element

{

public:

     virtual ~ConcreateElementA() {}

 

     virtual void Accept(Visitor &rVisitor);

};

 

class ConcreateElementB

     : public Element

{

public:

     virtual ~ConcreateElementB() {}

 

     virtual void Accept(Visitor &rVisitor);

};

 

class Visitor

{

public:

     virtual ~Visitor(){}

 

     virtual void VisitConcreateElementA(ConcreateElementA *pConcreateElementA) = 0;

     virtual void VisitConcreateElementB(ConcreateElementB *pConcreateElementB) = 0;

 

protected:

     Visitor(){}

};

 

class ConcreateVisitorA

     : public Visitor

{

public:

     virtual ~ConcreateVisitorA(){}

 

     virtual void VisitConcreateElementA(ConcreateElementA *pConcreateElementA);

     virtual void VisitConcreateElementB(ConcreateElementB *pConcreateElementB);

};

 

class ConcreateVisitorB

     : public Visitor

{

public:

     virtual ~ConcreateVisitorB(){}

 

     virtual void VisitConcreateElementA(ConcreateElementA *pConcreateElementA);

     virtual void VisitConcreateElementB(ConcreateElementB *pConcreateElementB);

};

void ConcreateElementA::Accept(Visitor &rVisitor)

{

     rVisitor.VisitConcreateElementA(this);

}

 

void ConcreateElementB::Accept(Visitor &rVisitor)

{

     rVisitor.VisitConcreateElementB(this);

}

 

void ConcreateVisitorA::VisitConcreateElementA(ConcreateElementA *pConcreateElementA)

{

     std::cout << "VisitConcreateElementA By ConcreateVisitorA\n";

}

 

void ConcreateVisitorA::VisitConcreateElementB(ConcreateElementB *pConcreateElementA)

{

     std::cout << "VisitConcreateElementB By ConcreateVisitorA\n";

}

 

void ConcreateVisitorB::VisitConcreateElementA(ConcreateElementA *pConcreateElementA)

{

     std::cout << "VisitConcreateElementA By ConcreateVisitorB\n";

}

 

void ConcreateVisitorB::VisitConcreateElementB(ConcreateElementB *pConcreateElementA)

{

     std::cout << "VisitConcreateElementB By ConcreateVisitorB\n";

}

int main()

{

     Visitor *pVisitorA = new ConcreateVisitorA();

     Element *pElement = new ConcreateElementA();

 

     pElement->Accept(*pVisitorA);

 

     delete pElement;

     delete pVisitorA;

 

     return 0;

}

 

 

 

posted @ 2012-01-11 19:56 柳清风 阅读(156) | 评论 (0)编辑 收藏

模板方法(Template Method)模式:定义一个操作中的算法的骨架,而将一些步骤延

迟到子类中。

组成

1) 抽象类(Abstract Class):定义了一到多个的抽象方法,以供具体的子类来实现它们;

而且还要实现一个模板方法,来定义一个算法的骨架。该模板方法不仅调用前面的抽象

方法,也可以调用其他的操作,只要能完成自身的使命。

2) 具体类(Concrete Class):实现父类中的抽象方法以完成算法中与特定子类相关的步骤。

// 抽象基类,定义算法的轮廓

class AbstractClass

{

public:

     AbstractClass(){}

     virtual ~AbstractClass(){}

 

     // 这个函数中定义了算法的轮廓

     void TemplateMethod();

 

protected:

     // 纯虚函数,由派生类实现之

     virtual void PrimitiveOperation1() = 0;

     virtual void PrimitiveOperation2() = 0;

};

 

// 继承自AbstractClass,实现算法

class ConcreateClass

     : public AbstractClass

{

public:

     ConcreateClass(){}

     virtual ~ConcreateClass(){}

 

protected:

     virtual void PrimitiveOperation1();

     virtual void PrimitiveOperation2();

};

#include "TemplateMethod.h"

#include <iostream>

 

void AbstractClass::TemplateMethod()

{

     PrimitiveOperation1();

     PrimitiveOperation2();

}

 

void ConcreateClass::PrimitiveOperation1()

{

     std::cout << "PrimitiveOperation1 by ConcreateClass\n";

}

 

void ConcreateClass::PrimitiveOperation2()

{

     std::cout << "PrimitiveOperation2 by ConcreateClass\n";

}

int main()

{

     AbstractClass* pConcreateClass = new ConcreateClass;

     pConcreateClass->TemplateMethod();

 

     delete pConcreateClass;

 

     system("pause");

 

     return 0;

}

posted @ 2012-01-11 19:55 柳清风 阅读(140) | 评论 (0)编辑 收藏

策略模式(Strategy)属于对象行为型设计模式,主要是定义一系列的算法,把这些算

法一个个封装成拥有共同接口的单独的类,并且使它们之间可以互换。

策略模式由三个角色组成:

1) 算法使用环境(Context)角色:算法被引用到这里和一些其它的与环境有关的操作一起

来完成任务。

2) 抽象策略(Strategy)角色:规定了所有具体策略角色所需的接口。在java 它通常由接口

或者抽象类来实现。

3) 具体策略(Concrete Strategy)角色:实现了抽象策略角色定义的接口。

class Strategy

{

public:

     virtual ~Strategy(){}

 

     virtual void AlgorithmInterface() = 0;

};

 

class ConcreateStrategyA

     : public Strategy

{

public:

     virtual ~ConcreateStrategyA(){}

 

     virtual void AlgorithmInterface();

};

 

class Context

{

public:

     Context(Strategy *pStrategy);

     ~Context();

 

     void ContextInterface();

private:

     Strategy* m_pStrategy;

};

 

Context::Context(Strategy *pStrategy)

     : m_pStrategy(pStrategy)

{

}

 

Context::~Context()

{

     delete m_pStrategy;

     m_pStrategy = NULL;

}

 

void Context::ContextInterface()

{

     if (NULL != m_pStrategy)

     {

         m_pStrategy->AlgorithmInterface();

     }

}

 

void ConcreateStrategyA::AlgorithmInterface()

{

     std::cout << "AlgorithmInterface Implemented by ConcreateStrategyA\n";

}

int main()

{

     Strategy* pStrategy = new ConcreateStrategyA();

     ContextpContext = new Context(pStrategy);

 

     pContext->ContextInterface();

 

     delete pContext;

 

     return 0;

}

posted @ 2012-01-11 19:54 柳清风 阅读(162) | 评论 (0)编辑 收藏

定义:允许一个对象在其内部状态改变时改变它的行为。

组成

1) 使用环境(Context)角色:客户程序是通过它来满足自己的需求。它定义了客户程序

需要的接口;并且维护一个具体状态角色的实例,这个实例来决定当前的状态。

2) 状态(State)角色:定义一个接口以封装与使用环境角色的一个特定状态相关的行为。

3) 具体状态(Concrete State)角色:实现状态角色定义的接口。

类图如下,结构非常简单也与策略模式非常相似。

class State;

 

class Context

{

public:

     Context(State* pState);

     ~Context();

     void Request();

     void ChangeState(State *pState);

 

private:

     State *m_pState;

};

class State

{

public:

     virtual ~State(){}

 

     virtual void Handle(Context* pContext) = 0;

};

 

class ConcreateStateA

     : public State

{

public:

     void Handle(Context* pContext);

};

 

class ConcreateStateB

     : public State

{

public:

     void Handle(Context* pContext);

};

 

Context::Context(State* pState)

     : m_pState(pState)

{

 

}

 

Context::~Context()

{

     delete m_pState;

     m_pState = NULL;

}

 

void Context::Request()

{

     if (NULL != m_pState)

     {

         m_pState->Handle(this);

     }

}

void Context::ChangeState(State *pState)

{

     if (NULL != m_pState)

     {

         delete m_pState;

         m_pState = NULL;

     }

    

     m_pState = pState;

 

void ConcreateStateA::Handle(Context* pContext)

{

     std::cout << "Handle by ConcreateStateA\n";

    

     if (NULL != pContext)

     {

         pContext->ChangeState(new ConcreateStateB());

     }

}

 

void ConcreateStateB::Handle(Context* pContext)

{

     std::cout << "Handle by ConcreateStateB\n";

 

     if (NULL != pContext)

     {

         pContext->ChangeState(new ConcreateStateA());

     }

}

int main()

{

     State *pState = new ConcreateStateA();

     Context *pContext = new Context(pState);

     pContext->Request();

     pContext->Request();

     pContext->Request();

 

     delete pContext;

 

     return 0;

}

posted @ 2012-01-11 19:54 柳清风 阅读(114) | 评论 (0)编辑 收藏

观察者(Observer)模式又名发布-订阅(Publish/Subscribe)模式。GOF 给观察者模

式如下定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依

赖于它的对象都得到通知并被自动更新

1) 抽象目标角色(Subject):目标角色知道它的观察者,可以有任意多个观察者观察同一

个目标。并且提供注册和删除观察者对象的接口。目标角色往往由抽象类或者接口来实

现。

2) 抽象观察者角色(Observer):为那些在目标发生改变时需要获得通知的对象定义一个

更新接口。抽象观察者角色主要由抽象类或者接口来实现。

3) 具体目标角色(Concrete Subject):将有关状态存入各个Concrete Observer 对象。当

它的状态发生改变时, 向它的各个观察者发出通知。

4) 具体观察者角色(Concrete Observer):存储有关状态,这些状态应与目标的状态保持

一致。实现Observer 的更新接口以使自身状态与目标的状态保持一致。在本角色内也

可以维护一个指向Concrete Subject 对象的引用。

 

#include <list>

 

typedef int STATE;

 

class Observer;

 

// Subject抽象基类,只需要知道Observer基类的声明就可以了

class Subject

{

public:

     Subject() : m_nSubjectState(-1){}

     virtual ~Subject();

 

     void Notify();                                 // 通知对象改变状态

     void Attach(Observer *pObserver);         // 新增对象

     void Detach(Observer *pObserver);         // 删除对象

 

     // 虚函数,提供默认的实现,派生类可以自己实现来覆盖基类的实现

     virtual void SetState(STATE nState); // 设置状态

     virtual STATE GetState();        // 得到状态

 

protected:

     STATE m_nSubjectState;                    // 模拟保存Subject状态的变量

     std::list<Observer*>   m_ListObserver;    // 保存Observer指针的链表

};

 

// Observer抽象基类

class Observer

{

public:

     Observer() : m_nObserverState(-1){}

     virtual ~Observer(){}

 

     // 纯虚函数,各个派生类可能有不同的实现

     // 通知Observer状态发生了变化

     virtual void Update(Subject* pSubject) = 0;

 

protected:

     STATE m_nObserverState;                   // 模拟保存Observer状态的变量

};

 

// ConcreateSubject类,派生在Subject类

class ConcreateSubject

     : public Subject

{

public:

     ConcreateSubject() : Subject(){}

     virtual ~ConcreateSubject(){}

 

     // 派生类自己实现来覆盖基类的实现

     virtual void SetState(STATE nState); // 设置状态

     virtual STATE GetState();        // 得到状态

 

};

 

// ConcreateObserver类派生自Observer

class ConcreateObserver

     : public Observer

{

public:

     ConcreateObserver() : Observer(){}

     virtual ~ConcreateObserver(){}

 

     // 虚函数,实现基类提供的接口

     virtual void Update(Subject* pSubject);

};

/* --------------------------------------------------------------------

|    Subject类成员函数的实现

|

 ----------------------------------------------------------------------*/

 

void Subject::Attach(Observer *pObserver)

std::cout << "Attach an Observer\n";

 

     m_ListObserver.push_back(pObserver);

}

 

void Subject::Detach(Observer *pObserver)

{

     std::list<Observer*>::iterator iter;

     iter = std::find(m_ListObserver.begin(), m_ListObserver.end(), pObserver);

 

     if (m_ListObserver.end() != iter)

     {

         m_ListObserver.erase(iter);

     }

 

     std::cout << "Detach an Observer\n";

}

 

void Subject::Notify()

{

     std::cout << "Notify Observers's State\n";

 

     std::list<Observer*>::iterator iter1, iter2;

 

     for (iter1 = m_ListObserver.begin(), iter2 = m_ListObserver.end();

          iter1 != iter2;

          ++iter1)

     {

         (*iter1)->Update(this);

     }

}

 

void Subject::SetState(STATE nState)

{

     std::cout << "SetState By Subject\n";

     m_nSubjectState = nState;

}

 

STATE Subject::GetState()

{

     std::cout << "GetState By Subject\n";

     return m_nSubjectState;

}

 

Subject::~Subject()

{

     std::list<Observer*>::iterator iter1, iter2, temp;

 

     for (iter1 = m_ListObserver.begin(), iter2 = m_ListObserver.end();

         iter1 != iter2;

         )

     {

         temp = iter1;

         ++iter1;

         delete (*temp);

     }

 

     m_ListObserver.clear();

}

 

/* --------------------------------------------------------------------

|    ConcreateSubject类成员函数的实现

|

----------------------------------------------------------------------*/

void ConcreateSubject::SetState(STATE nState)

{

     std::cout << "SetState By ConcreateSubject\n";

     m_nSubjectState = nState;

}

 

STATE ConcreateSubject::GetState()

{

     std::cout << "GetState By ConcreateSubject\n";

     return m_nSubjectState;

}

 

/* --------------------------------------------------------------------

|    ConcreateObserver类成员函数的实现

|

----------------------------------------------------------------------*/

void ConcreateObserver::Update(Subject* pSubject)

{

     if (NULL == pSubject)

         return;

 

     m_nObserverState = pSubject->GetState();

 

     std::cout << "The ObeserverState is " << m_nObserverState << std::endl;

}

 

int main()

{

     Observer *p1 = new ConcreateObserver;

     Observer *p2 = new ConcreateObserver;

 

     Subject* p = new ConcreateSubject;

     p->Attach(p1);

     p->Attach(p2);

     p->SetState(4);

     p->Notify();

 

     p->Detach(p1);

     p->SetState(10);

     p->Notify();

 

     delete p;

 

     system("pause");

 

     return 0;

}


posted @ 2012-01-11 19:53 柳清风 阅读(150) | 评论 (0)编辑 收藏

备忘录械(MEmento)模式又称标记(Token)模式。定义:在不破坏封闭性的前提下,捕获一个对象的内部状态,并在该对象之 外保存这个状态。这样以后就可将该对象到原先保存的状态。

组成:

1.       备忘录(Memento)角色:备忘录角色存储“备忘发起角色”的内部状态。

2.       备忘发起(Originator)角色:“备忘发起角色”创建一个备忘录,用以记录当前时刻它的内部状态。在需要时使用备忘录恢复内部状态。

3.       备忘录管理者(Caretaker)角色:负责保存好备忘录。不能对备忘录的内容进行操作或检查。

 

typedef std::string State;

class Memento;

Class Originator{

Originator(const Sate& rState)

: m_State(rState)

{

}

Originator(){}

~Originator(){}

 

Memnto* CreateMemento(){return new Memento(m_State); }

Void SetMemento(Memento *pMemento){}

State GetState(){return m_State; }

Void SetState(const State& rState){ m_State = rState; }

Void RestoreState(Memento* pMemento){

if (NULL != pMemento)

     {

         m_State = pMemento->GetState();

     }   

}

Void PrintState()

{

std::cout << "State = " << m_State << std::endl;

}

};

Class Memento{

Private:

Friend class Originator;

Memento(const State& rState)

{

}

Void SetState(const State& rState)

: m_State(rState)

{

}

State GetState()

{

return m_State;

}

State m_State;

};

int main()

{

     // 创建一个原发器

     Originator* pOriginator = new Originator("old state");

     pOriginator->PrintState();

// 创建一个备忘录存放这个原发器的状态

     Memento *pMemento = pOriginator->CreateMemento();

// 更改原发器的状态

     pOriginator->SetState("new state");

     pOriginator->PrintState();

     // 通过备忘录把原发器的状态还原到之前的状态

     pOriginator->RestoreState(pMemento);

     pOriginator->PrintState();

 

     delete pOriginator;

     delete pMemento;

 

     return 0;

}

posted @ 2012-01-11 19:52 柳清风 阅读(158) | 评论 (0)编辑 收藏

定义 用一个调停对象来封闭一系列的对象交互。

组成

1 抽象者调停者(Mediator)角色:调停者角色定义统一的接口用于各同事角色之间的通信。

2 具体调停者(Concrete Mediator)角色: 具体调停者角色通过协调各同事角色实现协作行为。为此它要知道并引用各个同事角色。

3 同事(Colleague)角色: 每一个同事角色都知道对应的具体调停者角色,而且与其他的同事通信的时候,一定要通过调停者角色协作。

 

Public Colleague{

Prvate:

 Mediator mediator;

Public:

Colleague(Mediator mediator)

{

Mediator = mediator;

}

Mediator getMediator() const

{

Return mediator;

}

Virtual void action() = 0;

};

Class Landlord:public Colleague{

Void action()

{

Cout<<”进行房间资料交给中介操作,省略”;

}

};

 

Class Lodger:public Colleague{

Void action()

{

Cout<<”进行将租房需求交给中介等操作”;

}

};

 

Class Mediator{

Virtual void colleagueChanged(Colleague *colleague) = 0;

};

Class ConcreteMediator:public Mediator{

Private:

Landlord *landlord;

Lodger *lodger;

Void colleagueChanged(Colleague *colleague)

{

 Landlord->action();

Lodger->action();

}

ConcreteMediator()

{

Landlord = new Landlord();

Lodger = new lodger();

}

~ ConcreteMediator()

{

Delete Landlord;

Delete Lodger;

}

};

 

 


posted @ 2012-01-11 19:51 柳清风 阅读(239) | 评论 (0)编辑 收藏

2012年1月4日

定义:提供一种方法访问一个容器(container)对角中的各个元素,而又不需要暴露该对象的内部细节。
组成:
1.迭代器角色(Iterator):迭代器角色负责定义访问和遍历元素的接口。
2.具体迭代器角色(Concrete Iterator):具体失口角色要实现迭代器接口,并要记录遍历中的当前位置。
3.容器角色(Container):窗口角色负责提供创建具体迭代器角色的接口。
4.具体容器角色(Concrete Container):具体窗口角色实现创建具体迭代器角色的接口---这个具体迭代器角色于该窗口的结构相关。
四、 实现自己的迭代器
在实现自己的迭代器的时候,一般要操作的容器有支持的接口才可以。而且我们还要注
意以下问题:
在迭代器遍历的过程中,通过该迭代器进行容器元素的增减操作是否安全呢?
在容器中存在复合对象的情况,迭代器怎样才能支持深层遍历和多种遍历呢?
以上两个问题对于不同结构的容器角色,各不相同,值得考虑。
五、 适用情况
由上面的讲述,我们可以看出迭代器模式给容器的应用带来以下好处:
1) 支持以不同的方式遍历一个容器角色。根据实现方式的不同,效果上会有差别。
2) 简化了容器的接口。但是在java Collection 中为了提高可扩展性,容器还是提供了遍历
的接口。
3) 对同一个容器对象,可以同时进行多个遍历。因为遍历状态是保存在每一个迭代器对象
中的。
由此也能得出迭代器模式的适用范围:
1) 访问一个容器对象的内容而无需暴露它的内部表示。
2) 支持对容器对象的多种遍历。
3) 为遍历不同的容器结构提供一个统一的接口(多态迭代)。


例子:

// 容器的抽象基类
class Aggregate
{
public:
 virtual ~Aggregate(){}

 virtual Iterater* CreateIterater(Aggregate *pAggregate) = 0;
 virtual int GetSize() = 0;
 virtual DATA GetItem(int nIndex) = 0;
};

// 迭代器的抽象基类
class Iterater
{
public:
 virtual ~Iterater(){}

 virtual void First()  = 0;
 virtual void Next()   = 0;
 virtual bool IsDone()  = 0;
 virtual DATA CurrentItem() = 0;

private:
};


// 一个具体的容器类,这里是用数组表示
class ConcreateAggregate
 : public Aggregate
{
public:
 ConcreateAggregate(int nSize)
: m_nSize(nSize)
 , m_pData(NULL)
{
 m_pData = new DATA[m_nSize];
 
 for (int i = 0; i < nSize; ++i)
 {
  m_pData[i] = i;
 }
}
 virtual ~ConcreateAggregate();

 virtual Iterater* CreateIterater(Aggregate *pAggregate)
{
return new ConcreateIterater(this);
}
 virtual int GetSize()
{
return m_nSize;
}
 virtual DATA GetItem(int nIndex)
{
 if (nIndex < m_nSize)
 {
  return m_pData[nIndex];
 }
 else
 {
  return -1;
 }
}

private:
 int m_nSize;
 DATA *m_pData;
};

// 访问ConcreateAggregate容器类的迭代器类
class ConcreateIterater
 : public Iterater
{
public:
 ConcreateIterater(Aggregate* pAggregate)
 : m_pConcreateAggregate(pAggregate)
 , m_nIndex(0)
{
}
 virtual ~ConcreateIterater(){}

 virtual void First()
{
m_nIndex = 0;
}
 virtual void Next()
{
 if (m_nIndex < m_pConcreateAggregate->GetSize())
 {
  ++m_nIndex;
 }
}
 virtual bool IsDone()
{
 return m_nIndex == m_pConcreateAggregate->GetSize();
}

 virtual DATA CurrentItem()
{
 return m_pConcreateAggregate->GetItem(m_nIndex);
}

private:
 Aggregate  *m_pConcreateAggregate;
 int   m_nIndex;
};

 

int main()
{
 Aggregate* pAggregate = new ConcreateAggregate(4);
 Iterater*  pIterater  = new ConcreateIterater(pAggregate);

 for (; false == pIterater->IsDone(); pIterater->Next())
 {
  std::cout << pIterater->CurrentItem() << std::endl;
 }

 return 0;
}

posted @ 2012-01-04 22:20 柳清风 阅读(192) | 评论 (0)编辑 收藏
仅列出标题  下一页

统计