Date post: | 05-Jan-2016 |
Category: |
Documents |
Upload: | betty-bryant |
View: | 212 times |
Download: | 0 times |
Behavioral Pattern: Strategy
Ch
ap
ter 5
– Pag
e
1
The Open-Closed Principle advocates designing software in such a way that it will absorb new variations without having to introduce new fundamental structure, enabling the capabilities of a system to be extended without substantially changing the basic system.The Strategy Pattern attempts to accomplish this by encapsulating each algorithm in a family of algorithms and making them all interchangeable, thus allowing each algorithm to vary independently of the clients that use it.This permits a program to switch
easily between algorithms without resorting to monolithic if-else statements.This approach allows the behavior in question to be modified at run-time and not just at design time.
The Strategy Pattern
Ch
ap
ter 5
– Pag
e
2
The Strategy declares an interface common to all supported algorithms, using this interface to call the algorithm defined by a ConcreteStrategy.The ConcreteStrategy implements the algorithm using the Strategy interface.
The Context is configured with a ConcreteStrategy object, maintains a reference to a Strategy object, and may define an interface that lets the Strategy object access its data.
ConcreteStrategyA
AlgorithmInterface()
ConcreteStrategyB
AlgorithmInterface()
ConcreteStrategyC
AlgorithmInterface()
Strategy
AlgorithmInterface()
Context
ContextInterface()
+strategy
Ch
ap
ter 5
– Pag
e
3Non-Software Example:Airport Transportation
Modes of transportation to an airport is an example of a Strategy.
PersonalVehicle
Transport()
Taxicab
Transport()
Limousine
Transport()
Strategy
Transport()
AirportTransportation
GoToAirport(Time, Cost)
+strategy
HotelShuttleBus
Transport()
Several options exist, such as driving one's own car, taking a taxi, an airport shuttle, or a limousine service.For some airports, subways and helicopters are also available as a mode of transportation to the airport.Any of these modes of transportation will get a traveler to the airport, and they can be used interchangeably.The traveler must chose the Strategy based on tradeoffs between cost, convenience, and time.
Ch
ap
ter 5
– Pag
e
4Software Example: Event HandlerThe NetworkManagement context needs strategies for handling various events on the network.The Connection strategy is to respond by indicating a need for greater bandwidth. Path
HandleEvent()
Connection
HandleEvent()
LSP
lspID
HandleEvent()
NetworkManagementEventHandler
currentEvent
HandleEvent()
+strategy
+successor
The Path strategy is to respond by indicating a need for some alternative path through the network.The LSP strategy is to respond by indicating a need for an alternative path through the network that meets specific label switched path requirements.
(Note that this model utilizes both the Strategy Pattern and the Chain of Responsibility Pattern.)
Ch
ap
ter 5
– Pag
e
5Event Handler Strategy C++ Code#include <iostream>#include <string>using namespace std;
typedef int Event;const Event LINK_1_BROKEN = 1;const Event LINK_2_BROKEN = 2;const Event CONGESTION = 3;const Event No_Event_Support = -1;
class EventHandler{ public: explicit EventHandler(EventHandler* hdlr = 0, Event evt = No_Event_Support); virtual const bool HasEventSupport(Event evt); virtual void SetHandler(EventHandler* hdlr, Event evt); virtual void HandleEvent(Event evt); virtual ~EventHandler() { cout << "Now in the EventHandler destructor" << endl; }; private: EventHandler* successor; Event currentEvent;};
Ch
ap
ter 5
– Pag
e
6//Set up a chain of event handlersEventHandler::EventHandler( EventHandler* hdlr, Event evt ) : successor(hdlr), currentEvent(evt) { }
const bool EventHandler::HasEventSupport(Event incomingEvent) { return currentEvent == incomingEvent;}
void EventHandler::SetHandler(EventHandler* hdlr, Event evt){ successor = hdlr; currentEvent = evt;}
void EventHandler::HandleEvent (Event incomingEvent){ if (incomingEvent != currentEvent) { if (successor != 0) { cout << "HandleEvent () calling into successor" << endl; successor->HandleEvent(incomingEvent); } } else { cout << "Base class help now follows" << endl; }}
Ch
ap
ter 5
– Pag
e
7class Connection : public EventHandler { public: Connection(Event evt) : EventHandler(0, evt) { } virtual void HandleEvent(Event incomingEvent);};
void Connection::HandleEvent(Event incomingEvent){ if (HasEventSupport(incomingEvent)) { // Offer event support cout << "Here's some Connection Event support" << endl; cout << "You may need additional bandwidth" << endl << endl; } else { cout << "No support from Connection - Sorry!" << endl; cout << "Calling the base class event handler" << endl; EventHandler::HandleEvent(incomingEvent); }}
Ch
ap
ter 5
– Pag
e
8class Path : public Connection{ public: Path::Path(Connection* conx, Event evt) : Connection(0) { cout << "In the Path constructor" << endl; SetHandler(conx, evt); }
void HandleEvent(Event incomingEvent) { if (HasEventSupport(incomingEvent)) { // Offer event support cout << "Here's some Path Event support" << endl; cout << "We need a new path" << endl << endl; } else { cout << "No support from Path - Sorry!" << endl; cout << "Calling the base class event handler" << endl; EventHandler::HandleEvent(incomingEvent); } }};
Ch
ap
ter 5
– Pag
e
9class Lsp : public Connection { public: Lsp::Lsp(string lspID, Connection* conx, Event evt) : Connection(0) { cout << "Constructing Lsp: " << lspID << endl; lspName = lspID; SetHandler(conx, evt); }
void HandleEvent(Event incomingEvent) { if (HasEventSupport(incomingEvent)) { // Offer event support cout << "At last, here's some LSP Event support:" << endl; cout << "We need an alternative path for " << lspName << endl << endl; } else EventHandler::HandleEvent(incomingEvent); }
private: string lspName;};
Ch
ap
ter 5
– Pag
e
10void main()
{ // Set up a Path->LSP->Connection Chain of Responsibility Connection* connection = new Connection(CONGESTION); Lsp* lsp = new Lsp("LSP123", connection, LINK_1_BROKEN); Path* path = new Path(lsp, LINK_2_BROKEN); cout << endl << "Time to handle network events" << endl << endl;
//A network event has occurred, e.g., CONGESTION //Let's see who can handle this event cout << "Let's simulate a network error: CONGESTION" << endl; path->HandleEvent(CONGESTION);
//Another network event has occurred, e.g., LINK_1_BROKEN //Let's see who can handle this event cout << "Let's simulate another network error: LINK_1_BROKEN" << endl; path->HandleEvent(LINK_1_BROKEN);
cout << "Let's simulate one more network error: LINK_2_BROKEN" << endl; path->HandleEvent(LINK_2_BROKEN);
delete path; delete lsp; delete connection;}
Ch
ap
ter 5
– Pag
e
11
Strategy Pattern Advantages
Ch
ap
ter 5
– Pag
e
12
• With the Strategy Pattern, a family of algorithms can be defined as a class hierarchy and can be used interchangeably to alter an application’s behavior without changing its architecture.
• By encapsulating the algorithm separately, new algorithms complying with the same interface can easily be introduced.• The application can switch strategies at run-time, and clients can choose the required algorithm without using a “switch” statement or a series of “if-else” statements.• Data structures used for implementing the algorithm are completely encapsulated in Strategy classes, so the implementation of an algorithm can be changed without affecting the Context class.