Sei sulla pagina 1di 16

Table of Contents

Object-Oriented Network  Overview


Programming with C++ { Recognizing patterns
{ Types of patterns

Design Patterns for Initializing


 Passively initializing network services
Network Services in OO { Overview of tactical patterns
Communication Frameworks
{ Overview of strategic patterns

Douglas C. Schmidt  Implementing the Acceptor pattern


schmidt@cs.wustl.edu { First implementation
{ Revised implementation
Washington University
 Summary
1 2

Identifying Common Behavior and


Introduction Structure
 Design patterns capture successful solutions  \Pattern recognition" occurs by observing
to recurring problems that arise during soft- recurring solution strategies
ware development
 e.g., network servers often look as follows:
 Useful design patterns and design pattern
descriptions, like useful software, evolve over void do_server (void) {
time listener_handle.initialize ();

{ Likewise, patterns build upon other patterns to for (;;) {


form families of related patterns // Create service to handle connection.
service = new Service;

// Wait for and accept connection.


client_handle = listener_handle.accept ();
 The following material captures the evolu-
tion of design patterns that are useful for // Activate service.
service->open (client_handle);
managing the lifecycle of services in OO // Perform service.
communication software service->run ();
}
}

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

 Strategic and tactical design patterns re-


move these limitations and decrease cou-  It is important to understand both types of
pling patterns
5 6

Decoupling IPC Mechanisms


 Problem
{ IPC mechanisms like sockets, TLI, and STREAM
The Wrapper Pattern
pipes have non-uniform interfaces, even though
they behavior similarly  Intent
{ Encapsulate lower-level functions within type-safe,
 Key forces modular, and portable class interfaces
{ Many IPC mechanisms (or subsets of mechanisms)
provide logically equivalent services even though  This pattern resolves the following force that
their interfaces are physically di erent arises when using native C-level OS APIs
. e.g., TLI vs. sockets 1. How to avoid tedious, error-prone, and non-portable
programming of low-level IPC mechanisms
{ Many IPC mechanisms are written in low-level C
code 2. How to combine multiple related, but independent,
functions into a single cohesive abstraction
 Solution
{ Use the Wrapper and Adapter patterns

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()

 This pattern resolves the following force that


Wrappee
arises when using conventional OS inter-
faces
specific_request() 1. `How to provide an interface that expresses the
similarities of seemingly di erent OS mechanisms
(such as networking or locking)

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 inde nitely 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

2. How to extend application behavior without requir-


ing changes to the event demultiplexing/dispatching
framework
 Participants in the Reactor pattern

13 14

Collaborations Decoupling Connection and


callback :
Service Handling Strategies
main Concrete reactor
program Event_Handler : Reactor
INITIALIZATION

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 a ecting 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 di er-
ent IPC mechanisms handle_event()

3. How to ensure that a passive-mode descriptor is


not accidentally used to read or write data
4. How to enable exible strategies for creation, con-
nection establishment, and concurrency

17 18

Structure of the First Acceptor


Pattern Implementation
First Implementation of the
Acceptor Pattern Concrete_Svc_Handler
APPLICATION

n SOCK Stream
1 SOCK_Acceptor
LAYER

Concrete Concrete
Svc Handler Acceptor
 The following slides illustrate an implemen-
tation of the Acceptor pattern ACTIVATES

{ This solution relies upon an implementation of the


Reactor pattern, as well as the Adapter pattern Svc
PEER_STREAM
SVC_HANDLER
A PEER_ACCEPTOR
CONNECTION

Handler Acceptor
LAYER

A
open()
 Subsequent slides will describe limitations handle_event()

with this rst approach


sh = new SVC_HANDLER;
peer_acceptor.accept(*sh);
reactor->register_handler (sh);

 Other tactical patterns will be used to re-


REACTIVE

move these limitations Event


LAYER

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 *);

// Creates, accepts, and activates SVC_HANDLER's.


virtual int handle_event (HANDLE); LOGGING
RECORDS
// Demultiplexing hooks.
LOGGING CONNECTION SERVER
virtual HANDLE get_handle (void) const;
RECORDS REQUEST

private: CLIENT
// Passive connection mechanism.
PEER_ACCEPTOR peer_acceptor_; CLIENT CLIENT
// Event demultiplexor.
Reactor *reactor_;
};

21 22

Acceptor Use-case Code


 Distributed logging server Acceptor Class Implementation
// Shorthand names.
class Logging_Handler :
#define SH SVC_HANDLER
public Svc_Handler<SOCK_Stream>
#define PR_AC PEER_ACCEPTOR
{
public:
// Initialize the Acceptor
// Obtain HANDLE.
virtual HANDLE get_handle (void) const;
template <class SH, class PR_AC> int
Acceptor<SH, PR_AC>::open (const PR_AC::ADDR &l_addr,
// Called back to process logging records.
Reactor *reactor)
virtual int handle_event (HANDLE);
{
};
this->reactor_ = reactor;
typedef Acceptor<Logging_Handler, SOCK_Acceptor>
// Forward to PEER_ACCEPTOR to advertise endpoint.
Logging_Acceptor;
this->peer_acceptor_.open (l_addr);
int main (void)
{
// Register with Reactor to listen for connections.
Reactor reactor;
Logging_Acceptor acceptor;
this->reactor_->register_handler
(this, READ_MASK);
acceptor.open (LOGGER_PORT, &reactor);
}
for (;;)
reactor.handle_events ();
}

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

// Accept connections from clients REGISTER HANDLER


register_handler(sh)
FOR CLIENT I/O
get_handle()
this->peer_acceptor_.accept (*svc_handler); EXTRACT HANDLE

handle_input()
DATA EVENT

PROCESSING
// Register SVC_HANDLER with Reactor.

SERVICE
svc()

PHASE
PROCESS MSG

this->reactor_->register_handler CLIENT SHUTDOWN handle_close()


(svc_handler, READ_MASK); SERVER SHUTDOWN handle_close()
}

 Acceptor factory creates, connects, and ac-


tivates a Svc Handler
25 26

Limitations with the First Overcoming Limitations with


Solution Patterns
 Several problems with the solution above:
 To remove the limitations described above,
1. Advertisement and listener strategies are hardcoded we'll use various patterns to enhance our
2. Service handler creation strategy is tightly cou- Acceptor
pled to dynamic allocation and constructor-based
initialization  Key patterns are Strategy, Bridge, Factory
Method, and Abstract Factory
3. Connection acceptance strategy is hard-coded
{ These are \tactical" patterns that are widely ap-
4. Service handler activation is not extensible and plicable across most application domains
concurrency strategy is overly restrictive
 Note that the new solution does not break
existing code
 This tight coupling makes it hard to extend
the Acceptor to work in other contexts { This is another important non-functional \force": : :

27 28
The Strategy Pattern Structure of the Strategy Pattern
 Intent STRATEGY

Context Strategy
{ De ne 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

Using the Strategy Pattern The Bridge Pattern


 Intent
SVC_HANDLER

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

Process 1. How to provide a stable, uniform interface that is


SVC_HANDLER SVC_HANDLER
Strategy both closed and open, i.e.,
Reactive Thread
Strategy Strategy { Closed to prevent direct code changes
{ Open to allow extensibility

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

The Template Method


 Intent The Factory Method Pattern
{ De ne the skeleton of an algorithm in an opera-
tion, deferring some steps to subclasses  Intent
. Template Method lets subclasses rede ne cer- { De ne an interface for creating an object, but let
tain steps of an algorithm without changing the subclasses decide which class to instantiate
algorithm's structure
. Factory Method lets a class defer instantiation
to subclasses
 This pattern resolves the following force
1. How to extend the strategies for creating the check sort  This pattern resolves the following force in
algorithm the Acceptor pattern:
1. How to extend each initialization strategy in the
Acceptor pattern independently and transparently
 Template Method is an alternative for the
Strategy/Bridge patterns

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

Structure of the Abstract Factory


The Abstract Factory Pattern Pattern
 Intent Abstract Concrete
Factory_2
{ Provide an interface for creating families of related Factory
or dependent objects without specifying their con- make_product_A() Abstract
make_product_A()
make_product_B()
crete classes make_product_B()
A
Product_A
A

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

Structure of the Revised Acceptor Advantages of New Design


Pattern  Decouple advertisement strategy
{ e.g., use well-known ports or name server
APPLICATION

n SOCK Stream
1
Concrete_Svc_Handler
SOCK_Acceptor
Concrete
LAYER

Svc Handler Concrete


open()
Acceptor  Decouple listening strategy
{ e.g., using Reactor or some other demultiplexor
SVC_HANDLER
INITS PEER_ACCEPTOR
PEER_STREAM A
Acceptor
Svc
advertise_svc()
 Decouple service creation strategy
Handler
CONNECTION

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

Event Decouple service concurrency strategy


LAYER


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

Acceptor Class Implementation


// Shorthand names.
#define SH SVC_HANDLER

Strategy Factory Interface #define PA_AC PEER_ACCEPTOR


#define PA_AD PEER_ACCEPTOR::PEER_ADDR
// Initialize the Acceptor.
template <class SVC_HANDLER, // Type of service
class PEER_ACCEPTOR> // Accepts connections
template <class SH, class PR_AC> int
class Strategy_Factory {
Acceptor<SH, PR_AC>::open
public:
(const PR_AC::PEER_ADDR &local_addr,
Strategy_Factory
Strategy_Factory<SH, PR_AC> *strat_fact)
(Advertise_Strategy<PEER_ACCEPTOR::PEER_ADDR> *,
{
Listener_Strategy<PEER_ACCEPTOR> *,
// Initialize the strategies.
Creation_Strategy<SVC_HANDLER> *,
this->create_strat_ =
Accept_Strategy<SVC_HANDLER, PEER_ACCEPTOR> *,
strat_fact->make_creation_strategy ();
Concurrency_Strategy<SVC_HANDLER> *);
this->accept_strat_ =
strat_fact->make_accept_strategy ();
// Factory methods called by Acceptor::open().
this->concurrency_strat_ =
Advertise_Strategy *make_advertise_strategy (void);
strat_fact->make_concurrency_strategy ();
Listener_Strategy *make_listener_strategy (void);
this->listen_strat_ =
Creation_Strategy<SVC_HANDLER>
strat_fact->make_listener_strategy ();
*make_create_strategy (void);
this->advertise_strat_ =
Accept_Strategy<SVC_HANDLER, PEER_ACCEPTOR>
strat_fact->make_advertise_strategy ();
*make_accept_strategy (void);
Concurrency_Strategy<SVC_HANDLER>
// Advertise the service.
*make_concurrency_strategy (void);
this->advertise_svc (local_addr);

// Make a listener.
this->make_listener (this);
}

47 48
// Bridge method for creating a service handler.

template <class SH, class PA> SH *


Acceptor<SH, PA>::make_svc_handler (void)
// Implements the strategy for creating, connecting,
{
// and activating new SVC_HANDLER objects.
return this->creation_strategy_->make_svc_handler ();
}
template <class SH, class PR_AC> int
Acceptor<SH, PR_AC>::handle_event (HANDLE)
// Accept connections from clients (can be overridden).
{
// Create a new SVC_HANDLER.
template <class SH, class PA> int
Acceptor<SH, PA>::accept_svc_handler (SH *svc_handler)
SH *svc_handler = this->make_svc_handler ();
{
return this->accept_strategy_->
// Accept connection from client.
accept_svc_handler (svc_handler);
}
this->accept_svc_handler (svc_handler);
// Activate the service handler (can be overridden).
// Activate SVC_HANDLER.
template <class SH, class PA> int
this->activate_svc_handler (svc_handler);
Acceptor<SH, PA>::activate_svc_handler (SH *svc_handler)
}
{
return this->concurrency_strategy_->
activate_svc_handler (svc_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() }

// Register with a Reactor


int
Reactive_Listener_Strategy::make_listener
(Event_Handler *h)
PEER ACCEPTOR {
PEER ACCEPTOR
this->handle_ = h->get_handle ();
Reactive Threaded this->reactor_->register_handler (h, READ_MASK);
Listener Listener
}

Strategy Strategy // Remove from Reactor


Reactive_Listener_Strategy::~Reactive_Listener_Strategy
(void)
{
this->reactor_->remove_handler (this->handle_);
}

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 }

Strategy // Make a new SVC_HANDLER on-demand.


template <class SH> SH *
make_svc_handler()
Demand_Strategy<SH>::make_svc_handler (void) {
return new SH;
}
SVC_HANDLER

// Make a SVC_HANDLER by dynamically linking it.


SVC_HANDLER
Dynamic template <class SH> SH *
Demand SVC_HANDLER
Strategy Dynamic_Strategy<SH>::make_svc_handler (void) {
Strategy // Open the shared library.
Singleton void *handle = (void *) dlopen (this->shared_library_);

Strategy // Extract the factory function.


SH *(*factory)(void) = (SH *(*)(void))
dlsym (handle, this->factory_function_);

// Call factory function to get new SVC_Handler.


return (*factory)();
}

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);
}

// Implement "stateless connection" strategy


SVC_HANDLER
SVC_HANDLER template <class SH, class PR_AC> int
PEER_ACCEPTOR
PEER_ACCEPTOR CLNS_Strategy<SH, PR_AC>::accept_svc_handler
CONS (SH *svc_handler)

Strategy CLNS {
// ...
Strategy }

57 58

SVC HANDLER Concurrency Concurrency Strategy


Strategies Implementations
// Activate the SVC_HANDLER by calling it's open() method.

template <class SH> int


SVC_HANDLER Reactive_Strategy<SH>::activate_svc_handler
(SH *svc_handler, void *arg)
Concurrency {
Strategy A // Delegate control to the application-specific service
// handler.
activate_svc_handler()
return svc_handler->open (arg);
}
SVC_HANDLER
SVC_HANDLER
Process // Activate the SVC_HANDLER by first calling its open()
// method and then calling its activate() method to turn
Reactive Strategy // it into an active object.
Strategy
template <class SH> int
Thread_Strategy<SH>::activate_svc_handler
SVC_HANDLER SVC_HANDLER
(SH *svc_handler, void *arg)
Thread Thread {
// Initialize SVC_HANDLER.
Strategy Pool svc_handler->open (arg);
Strategy
// Turn the svc_handler into an active object (if it isn't
// already one as a result of the first activation...)
return svc_handler->activate ();
}

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)
{

Both strategic and tactical patterns are nec-


Reactor reactor;
Logging_Acceptor acceptor; 
Logging_Strategy strategy (/* ... */, &reactor);
essary to build exible and extensible solu-
acceptor.open (LOGGER_PORT, &strategy); tions
for (;;)
reactor.handle_events ();
}

61 62

Potrebbero piacerti anche