Beruflich Dokumente
Kultur Dokumente
3 4
Identifying Limitations with the Strategic and Tactical Patterns
Existing Solution
Strategic design patterns have an extensive
The solution above is limited by tightly cou- impact on the software architecture
pling: { Typically oriented to solutions in a particular do-
{ Choice of IPC mechanisms main
{ Connection and service handling strategies { e.g., Reactor and Acceptor pattern in the domain
of event-driven, connection-oriented communica-
{ Choice of demultiplexing strategy tion software
{ Choice of advertisement strategy
{ Choice of endpoint listening strategy Tactical design patterns have a relatively lo-
calized impact on a software architecture
{ Choice of service creation strategy
{ Typically domain-independent
{ Choice of connection acceptance strategy
{ Choice of service concurrency strategy { e.g., Wrapper, Adapter, Bridge, Factory Method,
and Strategy
7 8
Structure of the Wrapper Pattern
The Adapter Pattern
1: request () Intent
client Wrapper { Convert the interface of a class into another inter-
face client expects
request()
. Adapter lets classes work together that couldn't
otherwise because of incompatible interfaces
2: specific_request()
9 10
Decoupling Demultiplexing
Strategy
Structure of the Adapter Pattern
Problem
1: request () { Servers often must handle events from more than
one source
Target
client
request() = 0
A
Key forces
{ It is inecient to repeatedly \poll" each event
source and it is incorrect to block indenitely on
Adapter Adaptee any one source of events
request() specific_request()
2: specific_request() { Extensibility is limited if the demultiplexing code is
coupled with the application event handling code
Solution
{ Use the Reactor pattern
11 12
Structure
The Reactor Pattern
select (handles) Concrete
Intent foreach h in handles loop Event
AP
h->handle_event (type)
Handler
PL
AP
end loop
IC
PL
{ Decouple event demultiplexing and event handler
AT
IC
IO
AT
dispatching from the services performed in response
N-
IO
SP
N-
to events
EC
IN
IF
DE
IC
PE
Reactor
ND
EN
1
T
handle_events()
n
This pattern resolves the following forces register_handler(eh, type)
for event-driven software: remove_handler(eh, type) Event Handler
1
1. How to demultiplex multiple types of events from 1 handle_event(type)
multiple sources of events eciently within a single 1
get_handle()
thread of control n Handles A
13 14
INITIALIZE
Reactor() Problem
MODE
REGISTER HANDLER
register_handler(callback)
{ Coupling initialization strategies with the service
get_handle() handling makes it hard to change either one with-
EXTRACT HANDLE
handle_events()
out aecting the other
START EVENT LOOP
select()
HANDLING
FOREACH EVENT DO
handle_event() Key forces
EVENT
MODE
EVENT OCCURS
REMOVE HANDLER handle_close() { Services tend to change more often than connec-
tion establishment strategies
Solution
Dynamic interaction among participants in { Use the Acceptor pattern
the Reactor pattern
15 16
The Acceptor Pattern
Intent
{ Decouple the passive initialization of a service from
Structure of the Acceptor Pattern
the tasks performed once the service is initialized
Svc Handler
This pattern resolves the following forces Svc Handler Acceptor
for network servers using interfaces like sock-
ets or TLI: peer_stream_
ES peer_acceptor_
open() IVAT handle_event()
ACT
1. How to reuse passive connection establishment code
for each new service
2. How to make the connection establishment code Reactor
portable across platforms that may contain dier-
ent IPC mechanisms handle_event()
17 18
n SOCK Stream
1 SOCK_Acceptor
LAYER
Concrete Concrete
Svc Handler Acceptor
The following slides illustrate an implemen-
tation of the Acceptor pattern ACTIVATES
Handler Acceptor
LAYER
A
open()
Subsequent slides will describe limitations handle_event()
Handler Reactor
handle_event() n 1
19 20
Acceptor Class Interface Typical Acceptor Use-Case
A factory for initializing network services SERVER
passively LOGGING
DAEMON
: Logging
Acceptor
template <class SVC_HANDLER, // Type of service : Logging
class PEER_ACCEPTOR> // Accepts connections Handler
class Acceptor : public Event_Handler {
public: : Logging
// Initialize and register with Reactor. Handler : Reactor
virtual int open (const PEER_ACCEPTOR::PEER_ADDR &,
Reactor *);
private: CLIENT
// Passive connection mechanism.
PEER_ACCEPTOR peer_acceptor_; CLIENT CLIENT
// Event demultiplexor.
Reactor *reactor_;
};
21 22
23 24
Collaboration in the Acceptor
Pattern
acc : sh: reactor :
Server
Acceptor Svc_Handler Reactor
// Factory that create, connects, and activates new
open()
INITIALIZATION INITIALIZATION
// single-threaded SVC_HANDLER objects. INITIALIZE
register_handler(acc)
ENDPOINT
REGISTER HANDLER
PHASE
template <class SH, class PR_AC> int EXTRACT HANDLE
get_handle()
Acceptor<SH, PR_AC>::handle_event (HANDLE) handle_events()
START EVENT LOOP
{
FOREACH EVENT DO select()
// Create a new SVC_HANDLER.
handle_input()
CONNECTION EVENT
SVC_HANDLER *svc_handler = new SVC_HANDLER; sh = new SVC_HANDLER
ALLOCATE AND
SERVICE
accept(*sh)
PHASE
ACTIVATE OBJECT
handle_input()
DATA EVENT
PROCESSING
// Register SVC_HANDLER with Reactor.
SERVICE
svc()
PHASE
PROCESS MSG
27 28
The Strategy Pattern Structure of the Strategy Pattern
Intent STRATEGY
Context Strategy
{ Dene a family of algorithms, encapsulate each
one, and make them interchangeable context_interface() algorithm_interface()
A
. Strategy lets the algorithm vary independently
from clients that use it
Concrete Concrete
Strategy A Strategy C
Concrete
This pattern resolves the following force algorithm_interface() Strategy B algorithm_interface()
1. How to extend the policies for adversizing, listen- algorithm_interface()
ing, creating, accepting, and executing a service
hander without modifying the core Acceptor algo-
rithm
29 30
Acceptor
PEER_ACCEPTOR SVC_HANDLER { Decouple an abstraction from its implementation
Concurrency so that the two can vary independently
handle_event() Strategy
2: activate_svc_handler(sh)
activate_svc_handler()
A
This pattern resolves the following force that
...
1: activate_svc_handler(sh)
arises when building extensible software
... SVC_HANDLER
31 32
Using the Bridge Pattern
Structure of the Bridge Pattern
3: accept_svc_handler(sh)
SVC_HANDLER
A Acceptor PEER_ACCEPTOR
1: method_impl()
accept_svc_handler() Accept
Implementor accept_strategy_ Strategy
Abstraction handle_event()
method_impl() accept_svc_handler()
method()
A A
A
...
2: accept_strategy_->accept_svc_handler(sh) SVC_HANDLER
Concrete ... PEER_ACCEPTOR
ImplementorA CLNS Strategy
method_impl() Concrete 1: accept_svc_handler()
accept_svc_handler()
Refined ImplementorB
Abstraction SVC_HANDLER
PEER_ACCEPTOR
method_impl()
CONS Strategy
accept_svc_handler()
33 34
35 36
Using the Factory Method
Structure of the Factory Method Pattern
Pattern
SVC_HANDLER
Creator Creation
A
factory_method() = 0 Strategy
make_product() A
Svc make_svc_handler()
A
Product Handler
A Product *product = factory_method()
return product
Concrete
Svc Handler
Concrete
Creator
Demand
Concrete Strategy
factory_method()
Concrete Svc Handler make_svc_handler()
Product CREATES
return new Concrete_Product
CREATES
return new Concrete_Svc_Handler
37 38
Product_A2
This problem resolves the following forces
in the Acceptor pattern: Product_A1
Product_B2
1. How to simplify the interface to the Acceptor and
keep it from having a large number of individual Concrete
strategies Factory_1 Product_B1
make_product_A() Abstract
2. How to ensure that the selected strategies actually make_product_B()
Product_B
work together without con
ict A
39 40
Using the Abstract Factory
Pattern
Revised Acceptor Class Model
SVC_HANDLER
PEER_ACCEPTOR
SVC_HANDLER
Strategy 2:
sh = make_svc_handler();
accept_svc_handler (sh);
PEER_ACCEPTOR
Acceptor
Factory Logging_Handler
SOCK Acceptor
activate_svc_handler (sh);
1: advertise_svc()
open() make_listener()
handle_event()
make_creation_strategy()
make_concurrency_strategy()
Logging SVC_HANDLER
advertise_svc()
Acceptor Creation make_svc_handler()
...
A Strategy activate_svc_handler()
accept_svc_handler() Advertise
make_svc_handler() make_listener() Strategy
...
A
advertise_svc()
SVC_HANDLER A
SVC_HANDLER PEER_ACCEPTOR
Logging_Handler Dynamic Listener
Concurrency Accept
SOCK Acceptor Strategy
Strategy Strategy Strategy
Logging activate_svc_handler() accept_svc_handler()
make_listener()
Strategies A A
A
make_creation_strategy() Reactive
make_concurrency_strategy() Strategy
...
41 42
n SOCK Stream
1
Concrete_Svc_Handler
SOCK_Acceptor
Concrete
LAYER
open()
make_listener() { e.g., dynamic allocation vs singleton or dynamic
LAYER
A make_svc_handler()
accept_svc_handler()
linking vs. static linking
activate_svc_handler()
open()
handle_event() Decouple service connection acceptance strat-
sh = make_svc_handler();
egy
accept_svc_handler (sh);
activate_svc_handler (sh); { e.g., connection-oriented vs. connectionless
REACTIVE
Handler Reactor
handle_event() n 1
{ e.g., single-threaded reactive vs. multi-threaded
vs. multi-process
43 44
Revised Acceptor Class Protected
Revised Acceptor Class Public and Private Interface
Interface protected:
// = Bridge methods (default behavior delegates
template <class SVC_HANDLER, // Type of service // to the Strategy objects...)
class PEER_ACCEPTOR> // Accepts connections virtual int advertise_svc (const PEER_ACCEPTOR::PEER_ADDR &);
class Acceptor : public Event_Handler { virtual int make_listener (Event_Handler *);
public: virtual SVC_HANDLER *make_svc_handler (void);
// = Initialization. virtual int accept_svc_handler (SVC_HANDLER *);
virtual int open virtual int activate_svc_handler (SVC_HANDLER *);
(const PEER_ACCEPTOR::PEER_ADDR &,
Strategy_Factory<SVC_HANDLER, PEER_ACCEPTOR> *); private:
// = Strategy objects.
// = Factory that creates, connects, Advertise_Strategy<PEER_ACCEPTOR::PEER_ADDR>
// and activates SVC_HANDLER's. *advertise_strat_;
virtual int handle_event (HANDLE); Listener_Strategy<PEER_ACCEPTOR> *listen_strat_;
Creation_Strategy<SVC_HANDLER> *create_strat_;
// = Demultiplexing hooks. Accept_Strategy<SVC_HANDLER, PEER_ACCEPTOR>
virtual HANDLE get_handle (void) const; *accept_strat_;
virtual int handle_close (HANDLE, Reactor_Mask); Concurrency_Strategy<SVC_HANDLER>
*concurrency_strat_;
};
45 46
// Make a listener.
this->make_listener (this);
}
47 48
// Bridge method for creating a service handler.
49 50
Advertisement Strategies
Advertisement Strategy
ADDR Implementations
Advertise template <class PA_AD>
A
Strategy Well_Known_Address<PA_AD>::advertise_svc
(const PA_AD &local_addr)
advertise_svc() {
// Advertise the IP port and IP address.
this->advertise_endpoint (local_addr);
ADDR ADDR
}
Well-known X.500 template <class PA_AD>
Address Strategy Port_Mapper<PA_AD>::advertise_svc
Strategy ADDR (const PA_AD &local_addr)
{
Portmapper // Advertise using the portmapper
Strategy
// ...
}
51 52
Listener Strategies Listener Strategy
Implementations
// Cache a Reactor.
PEER ACCEPTOR template <class PA_AC>
Reactive_Listener_Strategy<PA_AC>::Listener_Strategy
A
Listener (Reactor *r)
Strategy : reactor_ (r)
{
make_listener() }
53 54
Creation Strategy
SVC HANDLER Creation Implementations
Strategies // Make a Singleton SVC_HANDLER.
template <class SH> SH *
Singleton_Strategy<SH>::make_svc_handler (void) {
if (this->svc_handler_ == 0)
this->svc_handler_ = new SH;
SVC_HANDLER return this->svc_handler_; // Pre-cached...
A Creation }
55 56
SVC HANDLER Connection
Acceptance Strategies
Connection Acceptance Strategy
SVC_HANDLER
Implementation
PEER_ACCEPTOR // Delegate to the accept() method of the PEER_ACCEPTOR.
Accept A
template <class SH, class PR_AC> int
Strategy Accept_Strategy<SH, PR_AC>::accept_svc_handler
(SH *svc_handler)
{
accept_svc_handler() return this->peer_acceptor_.accept (*svc_handler);
}
Strategy CLNS {
// ...
Strategy }
57 58
59 60
New Acceptor Use-Case
class Logging_Handler :
{
public Svc_Handler<SOCK_Stream>
Concluding Remarks
public:
// Initialize handler.
virtual int open (void *);
Design patterns can alleviate coupling and
// Obtain HANDLE. unnecessary complexity in communication
virtual HANDLE get_handle (void) const;
software
// Called back to process logging records.
virtual int handle_event (HANDLE);
}; Patterns do not exist in isolation
typedef Acceptor<Logging_Handler, SOCK_Acceptor> { Instead, they form \families of patterns" that build
Logging_Acceptor; upon each other
int main (void)
{
61 62