Chinaunix首页 | 论坛 | 博客
  • 博客访问: 845978
  • 博文数量: 756
  • 博客积分: 40000
  • 博客等级: 大将
  • 技术积分: 4980
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 14:40
文章分类

全部博文(756)

文章存档

2011年(1)

2008年(755)

我的朋友

分类:

2008-10-13 16:10:40

说明: 这个blog没办法贴图, 完整请见: http://hi.baidu.com/huangrg/blog/item/aa9e46c7feaeebdfd100608c.html
我家有: 老婆, 儿子, 女儿.
我考虑写一个程序模拟她们的生活.
抽象出老婆,儿子和女儿这三个对象,为了易于统一管理和访问这些对象,同时抽象了一些公共基类:Baby.Baby要提供所有可能的接口. 为了把问题简单化,假设老婆主要照顾两个小宝贝和做家务(^-^); 两个小宝贝还小,基本上就是玩.于是我们建立下面的类模型:



根据这个模型,我们可以发现一些不足的地方:

1)抽象接口提供所有子类的行为接口
抽象基类Baby为Wife,Son和Daughter提供了所有的接口,显得比较复杂。
2)子类必须要重写不属于自己的行为
比如儿子比较小,是不参与家务的,但在程序中,Son必须重写Housework(),只是什么都不做。当然,通过某些方式可以避免这问题出现,但同时也会带来其它新问题。
3)增加新的行为比较烦琐
在任何一个类中增加一个新行为,就要在所有的类中做修改。比如,小孩上小学了,老婆不须要照顾小孩了,要上班;同时儿子可能还要踢足球,女儿要课余要学唱歌、舞蹈等。系统不易扩展,增加新功能容易出错;而且会越来越复杂,不易维护。

有必要对设计进行优化,使系统更易扩展和维护。注意以上类结构的特点:Wife、Son、Daughter,这此元素比较稳定;但她们的行为容易变化。
因此我们很自然想到了采用Visitor,建立下面的类模型:

采用Visitor模式重新设计后,基本上消除了以上的不足之处。特别是要增加一个新行为,只要在Visitor层次增加一个新类,不会使系统越来越复杂。下面是针对采用Visitor后的代码实现。
说明:1)代码实现里的Visitor成员函数通过重载机制统一用Visit命名;
2)为编排简单,所有成员函数定义在类声明里实现.

以下是Visitor层次的代码:

struct Visitor
{
virtual void Visit(Wife& wife) = 0;
virtual void Visit(Son& son) = 0;
virtual void Visit(Daughter& daughter) = 0;
};

class BabysatVisitor : public Visitor
{
public:
virtual void Visit(Wife& wife)
{
std::cout << "Wife is taking care of son and daughter.\n";
}

virtual void Visit(Son& son){ }

virtual void Visit(Daughter& daughter){ }
};

HouseworkVisitor也是针对Wife的一个动作,实现和BabysatVisitor类似,略。

class PalyVisitor : public Visitor
{
public:
virtual void Visit(Wife& wife){ }

virtual void Visit(Son& son)
{
std::cout << "Son is playing.\n";
}

virtual void Visit(Daughter& daughter)
{
std::cout << "Daughter is playing.\n";
}
};

以下元素层次的代码:

struct Baby
{
virtual void Accept(Visitor& visitor) = 0;
};

class Wife : public Baby
{
public:
virtual void Accept(Visitor& visitor)
{
visitor.Visit(*this);
}
};

Son和Daughter用同样的方法实现Accept,略.

最后用Family管理她们。

class Family
{
public:

typedef std::multimap BabyMap;

Family()
{
babies_->insert(BabyMap::value_type(new Wife, new WifeVisitor));
babies_->insert(BabyMap::value_type(new Son, new SonVisitor));
babies_->insert(BabyMap::value_type(new Daughter, new DaughterVisitor));
}

void Behave()
{
for (BabyMap::const_iterator it = babies_.begin(); it != babies_.end(); ++it)
it->first->Accept(*it->second);
}
private:
BabyMap babies_;
};

主函数类似:

Family family;

family.Behave();

最后要说明的, 如果经常娶老婆或者经常有小宝宝出生的话,也就说像Wife这些节点容易变化的话, 使用Visitor模式不一定能带来多少好处.
--------------------next---------------------

1. 设计目标
       目标是易使用,高效率,库本身易扩展,提供有限的Socket功能支持。这套库提供同步和异步IO支持,单独提供Select功能。平台暂时支持Win32和Linux2.6。
        易使用主要是提供简单的接口。比如泛化了IO Model(这里IO Model只用于这套库:同步和异步)。
        高效率体现在使用Generic方法实现各个类,整个库没有涉及到虚函数的开销;为了避免异常的开销,这套库泛化错误处理,根据一个模板参数来决定用'return error code' 还是'throw exception';原本准备泛化IP地址,这样就可以同时支持IP4和IP6,但没有开发IP6程序,所以就暂时不处理这个任务。另外泛化了Socket 的类型。

2. 类结构
        不知道怎么把UML Diagram上传到这里,直接用代码说明。
        class socket_base;
       template
       class basic_socket : public socket_base;
        
        下面和UDP有关的类:
         template
       class basic_datagram_socket : public basic_socket;

        typedef basic_datagram_socket datagram_socket;
        typedef basic_datagram_socket async_datagram_socket;


         下面和TCP有关的类:
          template
        class basic_stream_socket : public basic_socket;

        template
        class basic_acceptor : public basic_stream_socket;
        template
        class basic_connector : public basic_stream_socket;
        template
        class basic_data_stream : public basic_stream_socket;

         typedef basic_acceptor acceptor;
         typedef basic_acceptor async_acceptor;

        还有一个Selector,当须要管理大量套接字,但效率不是很严格的时候,使用Selector可以带来一些好处。另外就是一些辅助类和内部实现类,这里就不列出了。
        和用户调用有关的类结构还是比较简单,我用basic_datagram_socket来解释一下。第一个模板参数:IOModel决定调用者是用同步还是异步IO;第二个模板参数:ErrorHandler决定当产生运行错误时,调用者要库返回错误码还是异常。
        typedef basic_datagram_socket datagram_socket;
        datagram_socket socket;
  
这个UDP socket对象用同步IO处理接收和发送,当产生运行时错误的话,就抛出socket_exception。一般用同步IO,效率不是考虑因素,所以抛出异常的方式处理错误。为了方便用户,这套库就typedef  datagram_socket和async_datagram_socket。请看一下,async_datagram_socket的第二个模板参数,用的是return_error_code,这样程序运行的时候具备更高的效率。

3. 典型的使用过程
        以connector为例,看看怎么样使用这套库。
        typedef argus::socket::basic_connector connector;
        data_stream stream;
        try
        {
                  connector conn;     // There can write so: connector conn('local ip', 'local port');
                  if (conn.connect('10.6.2.1', 8888, stream)) 
                 {  
                          // connect successfully
                  } 
        }
        catch (const argus::socket::socket_exception& e)    
        {
                   .....
         }

         using the stream  implement to send and receive data.

         这里还有一些细节须要进一步处理:主要是IO Model的问题,实现起来有点难度。

4. 后话
       目前这套库正针对Win32平台开发(但已经考虑了多平台支持),开发完了,测试稳定了,我就发布源码和文档,让大家帮忙改进。

        
 



--------------------next---------------------

阅读(385) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~