ACE
中的设计模式
(3)
——
Strategy
Joise.LI @ 2006-10-9,FYT04121
1.
Strategy
模式简介
Strategy模式定义了不同算法的接口,分别封装起来,让他们彼此之间可以互相替换,带来的好处是把系统中容易发生变化的部分与稳定的部分隔离开来,该模式对于后续的维护是非常有用的。
使用Strategy可以应对不稳定的需求,对于经常需要需求变更的部分,可以将改变的部分限制在Strategy,避免在整个系统中到处修改,导致一些意想不到的问题。
#include
<iostream>
using
namespace std;
class
base_sort
{
public
:
virtual void do_sort()
{
cout << "base sort" << endl;
}
};
class
half_sort : public base_sort
{
public
:
virtual void do_sort()
{
cout << "half sort" << endl;
}
};
class
quick_sort : public base_sort
{
public
:
virtual void do_sort()
{
cout << "quick sort" << endl;
}
};
class
my_vector
{
public
:
my_vector(base_sort *sort_strategy)
{
m_sort = sort_strategy;
}
void sort()
{
m_sort->do_sort();
}
protected
:
private
:
base_sort *m_sort;
};
int
main()
{
base_sort *sort_ = new quick_sort;
my_vector vector_(sort_);
vector_.sort();
return 0;
};
如上例如示,Strategy将排序这种不稳定的需求完美的封装起来了,后续如果有更高的性能需求,比如写出了常数时间排序算法,只需简单的修改代码为(修改部分标记为红色):
#include
<iostream>
using
namespace std;
class
base_sort
{
public
:
virtual void do_sort()
{
cout << "base sort" << endl;
}
};
class
half_sort : public base_sort
{
public
:
virtual void do_sort()
{
cout << "half sort" << endl;
}
};
class
quick_sort : public base_sort
{
public
:
virtual void do_sort()
{
cout << "quick sort" << endl;
}
};
class const_time_sort : public base_sort
{
public:
virtual void do_sort()
{
cout << "const_time_sort" << endl;
}
};
class
my_vector
{
public
:
my_vector(base_sort *sort_strategy)
{
m_sort = sort_strategy;
}
void sort()
{
m_sort->do_sort();
}
protected
:
private
:
base_sort *m_sort;
};
int
main()
{
base_sort *sort_ = new const_time_sort;
my_vector vector_(sort_);
vector_.sort();
return 0;
};
2.
ACE
中的Strategy
ACE
中很多地方都使用了Strategy模式,包括:
1.
Acceptor
2.
Connector
3.
Cache Manager
4.
dll Manager
5.
lock
6.
...
ACE
中使用Strategy的地方实在太多了,举不胜举,这里就拿Acceptor来举个例子吧——下例中代码参见.../ACE_wrappers/examples/Connection/misc/test_upipe.cpp:
class
Server : public ACE_Strategy_Acceptor <Server_Service, ACE_UPIPE_ACCEPTOR>
{
// = TITLE
// Defines the interface for a factory that accepts connections
// and creates/activates Server_Service objects.
public
:
Server (ACE_Thread_Manager *thr_mgr,
ACE_Reactor *reactor)
: reactor_ (reactor),
thr_mgr_ (thr_mgr)
{
ACE_TRACE ("Server::Server");
}
virtual int init (int argc, ACE_TCHAR *argv[])
{
ACE_TRACE ("Server::init");
const ACE_TCHAR *l_addr = argc > 1 ? argv[1] : ACE_DEFAULT_RENDEZVOUS;
ACE_UPIPE_Addr local_addr (l_addr);
if (this->thr_strategy_.open (this->thr_mgr_, THR_DETACHED | THR_NEW_LWP) == -1)
return -1;
else if (this->open (local_addr, this->reactor_,
0, 0, &this->thr_strategy_) == -1)
return -1;
// Give server a chance to register the STREAM pipe.
ACE_OS::sleep (ACE_Time_Value (4));
return 0;
}
private
:
ACE_Reactor *reactor_;
// Our instance of the reactor.
ACE_Thread_Manager *thr_mgr_;
// Our instance of a thread manager.
ACE_Thread_Strategy<Server_Service> thr_strategy_;
// Our concurrency strategy.
};
3.
ACE
的Strategy
是如何实现的?
以下代码节选自
ACE
的源代码,为清晰起见,只保留与
Strategy
相关的代码,同样,还是以
Acceptor
为例说明:
a) 以下是ACE_Strategy_Acceptor的定义:
template
<class SVC_HANDLER, ACE_PEER_ACCEPTOR_1>
class
ACE_Strategy_Acceptor
: public ACE_Acceptor <SVC_HANDLER, ACE_PEER_ACCEPTOR_2>
{
public:
...
typedef ACE_Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2> ACCEPT_STRATEGY;
...
ACE_Strategy_Acceptor (const ACE_PEER_ACCEPTOR_ADDR &local_addr,
ACE_Reactor * = ACE_Reactor::instance (),
ACE_Creation_Strategy<SVC_HANDLER> * = 0,
ACE_Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2> * = 0,
ACE_Concurrency_Strategy<SVC_HANDLER> * = 0,
ACE_Scheduling_Strategy<SVC_HANDLER> * = 0,
const ACE_TCHAR service_name[] = 0,
const ACE_TCHAR service_description[] = 0,
int use_select = 1,
int reuse_addr = 1);
virtual int open (const ACE_PEER_ACCEPTOR_ADDR &local_addr,
ACE_Reactor *reactor,
int flags = 0,
int use_select = 1,
int reuse_addr = 1);
virtual int open (const ACE_PEER_ACCEPTOR_ADDR &,
ACE_Reactor * = ACE_Reactor::instance (),
ACE_Creation_Strategy<SVC_HANDLER> * = 0,
ACE_Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2> * =0,
ACE_Concurrency_Strategy<SVC_HANDLER> * = 0,
ACE_Scheduling_Strategy<SVC_HANDLER> * = 0,
const ACE_TCHAR *service_name = 0,
const ACE_TCHAR *service_description = 0,
int use_select = 1,
int reuse_addr = 1);
...
protected
:
ACCEPT_STRATEGY *accept_strategy_;
};
b)
看一下open的实现:
template
<class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
ACE_Strategy_Acceptor
<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::open
(const ACE_PEER_ACCEPTOR_ADDR &local_addr,
ACE_Reactor *reactor,
int /* flags unused */,
int use_select,
int reuse_addr)
{
ACE_TRACE ("ACE_Strategy_Acceptor<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::open");
return this->open
(local_addr, reactor, 0, 0, 0, 0, 0, 0, use_select, reuse_addr);
}
template
<class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
ACE_Strategy_Acceptor
<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::open
(const ACE_PEER_ACCEPTOR_ADDR &local_addr,
ACE_Reactor *reactor,
ACE_Creation_Strategy<SVC_HANDLER> *cre_s,
ACE_Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2> *acc_s,
ACE_Concurrency_Strategy<SVC_HANDLER> *con_s,
ACE_Scheduling_Strategy<SVC_HANDLER> *sch_s,
const ACE_TCHAR *service_name,
const ACE_TCHAR *service_description,
int use_select,
int reuse_addr)
{
...
// Initialize the accept strategy.
if (acc_s == 0)
{
ACE_NEW_RETURN (acc_s,
ACCEPT_STRATEGY (this->reactor ()),
-1);
this->delete_accept_strategy_ = 1;
}
this->accept_strategy_ = acc_s;
if (this->accept_strategy_->open (local_addr, reuse_addr) == -1)
return -1;
// Set the peer acceptor's handle into non-blocking mode. This is a
// safe-guard against the race condition that can otherwise occur
// between the time when <select> indicates that a passive-mode
// socket handle is "ready" and when we call <accept>. During this
// interval, the client can shutdown the connection, in which case,
// the <accept> call can hang!
if (this->accept_strategy_->acceptor ().enable (ACE_NONBLOCK) != 0)
return -1;
...
return this->reactor ()->register_handler
(this, ACE_Event_Handler::ACCEPT_MASK);
}
说明:由上例代码可以看出,ACE_Strategy_Acceptor中组合了ACCEPT_STRATEGY *accept_strategy_对象,该对象负责处理accept事宜。
ACE_Strategy_Acceptor
在open的时候将相应的accept事件委托给
accept_strategy_
处理,从而实现动态的策略更换。
A.
下面再看一下ACE_Accept_Strategy的定义:
template
<class SVC_HANDLER, ACE_PEER_ACCEPTOR_1>
class
ACE_Accept_Strategy
{
public
:
// Useful STL-style traits.
typedef ACE_PEER_ACCEPTOR_ADDR addr_type;
typedef ACE_PEER_ACCEPTOR acceptor_type;
typedef SVC_HANDLER handler_type;
typedef ACE_TYPENAME SVC_HANDLER::stream_type stream_type;
// = Initialization and termination methods.
/// Default constructor.
ACE_Accept_Strategy (ACE_Reactor *reactor = ACE_Reactor::instance ());
/// Initialize the <peer_acceptor_> with <local_addr>.
ACE_Accept_Strategy (const ACE_PEER_ACCEPTOR_ADDR &local_addr,
int restart = 0,
ACE_Reactor *reactor = ACE_Reactor::instance ());
/// Initialize the <peer_acceptor_> with <local_addr>, indicating
/// whether to <reuse_addr> if it's already in use.
virtual int open (const ACE_PEER_ACCEPTOR_ADDR &local_addr,
int reuse_addr = 0);
/// Return the underlying ACE_HANDLE of the <peer_acceptor_>.
virtual ACE_HANDLE get_handle (void) const;
/// Return a reference to the <peer_acceptor_>.
virtual ACE_PEER_ACCEPTOR &acceptor (void) const;
virtual ~ACE_Accept_Strategy (void);
// = Factory method.
/// The default behavior delegates to the <accept> method of the
/// PEER_ACCEPTOR.
virtual int accept_svc_handler (SVC_HANDLER *);
/// Dump the state of an object.
void dump (void) const;
/// Declare the dynamic allocation hooks.
ACE_ALLOC_HOOK_DECLARE;
protected
:
/// Factory that establishes connections passively.
ACE_PEER_ACCEPTOR peer_acceptor_;
/// Pointer to the reactor used by the Acceptor.
ACE_Reactor *reactor_;
/// Needed to reopen the socket if <accept> fails.
int reuse_addr_;
/// Needed to reopen the socket if <accept> fails.
ACE_PEER_ACCEPTOR_ADDR peer_acceptor_addr_;
};
B.
再看一下ACE_Accept_Strategy的open实现:
template
<class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
ACE_Accept_Strategy
<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::open
(const ACE_PEER_ACCEPTOR_ADDR &local_addr, int reuse_addr)
{
this->reuse_addr_ = reuse_addr;
this->peer_acceptor_addr_ = local_addr;
if (this->peer_acceptor_.open (local_addr,
reuse_addr) == -1)
return -1;
// Set the peer acceptor's handle into non-blocking mode. This is a
// safe-guard against the race condition that can otherwise occur
// between the time when <select> indicates that a passive-mode
// socket handle is "ready" and when we call <accept>. During this
// interval, the client can shutdown the connection, in which case,
// the <accept> call can hang!
this->peer_acceptor_.enable (ACE_NONBLOCK);
return 0;
}
说明:如果对于accept有自己独特的需求,可以继承
ACE_Accept_Strategy
,并构造相应的对象并传递给ACE_Strategy_Acceptor,那么可以在不影响其它模块的情况下实现自己所独有的accept需求。
C.
题外话:
Strategy可以在灵活的替换容易受需求变更影响的模块内容,也可以在实现在运行时根据不同的情况灵活的选择相应的策略或算法,对于在需求变更时整个系统的稳定重构可以起比较大的作用,软件的需求唯一的不变就是变化,面对需求的不稳定性,可以考虑多使用Strategy来应对变化,最后感叹一句——尤其是在国内软件业当前状况下,对于需求的把握能力相当欠缺,Strategy可以减少后期相当大的维护量的。
后续我会继续就ACE中的使用的设计模式提出来与大家进行探讨、学习。
D.
作者相关信息:
欢迎大家与我交流,共同学习,共同提高。
joise@126.com,
http://joise.126.com