Design patterns part iii tic vii c10
Download
1 / 22

- PowerPoint PPT Presentation


  • 153 Views
  • Updated On :

Design Patterns Part III (TIC++VII:C10). Yingcai Xiao 07/08/08. What For How Examples. Outline. Simplifying Idioms Patterns to keep code simple and straightforward. Common task : to package information into an object.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about '' - ilithya


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
Design patterns part iii tic vii c10 l.jpg

Design Patterns Part III(TIC++VII:C10)

Yingcai Xiao

07/08/08


Outline l.jpg

Outline


Simplifying idioms patterns to keep code simple and straightforward l.jpg
Simplifying IdiomsPatterns to keep code simple and straightforward.


The messenger pattern l.jpg

  • Common task: to package information into an object.

  • Use: to pass information around in one piece instead of in separate pieces.

  • Implementation example: C10:MessengerDemo.cpp

  • class Point { // A messenger

  • public:

  • int x, y, z; // public for easier coding

  • Point(int xi, int yi, int zi) : x(xi), y(yi), z(zi) {} // init

  • Point(const Point& p) : x(p.x), y(p.y), z(p.z) {} // init

  • Point& operator=(const Point& rhs) { // assignment

  • x = rhs.x;y = rhs.y;z = rhs.z;return *this;

  • }

  • friend ostream&operator<<(ostream& os, const Point& p) {

  • return os << "x=" << p.x << " y=" << p.y<< " z=" << p.z; // display

  • }

  • };

The Messenger Pattern


The messenger pattern5 l.jpg

class Space {

public:

static Point translate(Point p, int dx, int dy, int dz) {

p.x += dx;p.y += dy;p.z += dz;return p;

}

};

int main() {

Point p1(1, 2, 3);

// a static method can be used without creating an object

Point p2 = Space::translate(p1, 3, 2, 1));

cout << "p1: " << p1 << " p2: " << p2 << endl;

}

The Messenger Pattern


The collecting parameter pattern l.jpg

  • Common task: collecting parameter is messenger’s big brother, it captures information from the function to which it is passed.

  • Use: to collect information from multiple functions.

  • Implementation example: C10:CollectingParameterDemo.cpp

The Collecting Parameter Pattern


The collecting parameter pattern7 l.jpg

class CollectingParameter : public vector<string> {}; // the class

class Filler {

public:

// the functions from which to collect information from

void f(CollectingParameter& cp) {cp.push_back("accumulating");}

void g(CollectingParameter& cp) { cp.push_back("items"); }

void h(CollectingParameter& cp) {cp.push_back("as we go");}

};

int main() {

Filler filler;

CollectingParameter cp;

filler.f(cp); filler.g(cp); filler.h(cp);

vector<string>::iterator it = cp.begin();

while(it != cp.end())cout << *it++ << " ";

cout << endl;

} ///:~

The Collecting Parameter Pattern


The singleton pattern l.jpg

  • Common task: to allow one and only one instance of a class

  • Use: to make sure there is no way to create more than one instance of a special class for each application (e.g. the eAF - Application Framework class in PA4. )

  • Implementation example: C10:SingletonPattern.cpp

  • class Singleton {

  • static Singleton s; // static: one copy per class, self declaration

  • int i; // a single data member for demonstration

  • Singleton(int x) : i(x) { }

  • Singleton& operator=(Singleton&); // Disallowed

  • Singleton(const Singleton&); // Disallowed

  • public:

  • static Singleton& instance() { return s; } // return the reference to the sole instance

  • int getValue() { return i; } // access its

  • void setValue(int x) { i = x; }

  • };

The Singleton Pattern


The singleton pattern9 l.jpg

// declaring s so that it can be referenced

Singleton Singleton::s(47);

int main() {

Singleton& s = Singleton::instance();

cout << s.getValue() << endl;

Singleton& s2 = Singleton::instance();

s2.setValue(9);

cout << s.getValue() << endl;

// the following will not compile

// Singleton *sp = new Singleton(); // no appropriate default constructor available

// Singleton *sp = new Singleton(8); //cannot access private member

// Singleton *sp = new Singleton(Singleton::instance()); // cannot access private member

} ///:~

The Singleton Pattern

C10:SingletonPattern.cpp


The singleton pattern10 l.jpg

  • The key to creating a Singleton is to prevent the client programmer from having any control over the lifetime of the object.

    • declare all constructors private (note: a private constructor can’t be used to create new objects, but can be used to declare an static object).

    • prevent the compiler from implicitly generating any constructors (compiler will not create a default construct if there is any kind of constructors there).

    • The copy constructor and assignment operator (which intentionally have no implementations, since they will never be called) are declared private to prevent any sort of copies being made.

  • You must also decide how to create the single instance of the class. Here, it’s created statically. Lazy initialization waits until the client programmer asks for one and create it on demand. Tt only makes sense if it is expensive to create your object, and if you don’t always need it.

  • If you return a pointer instead of a reference, the user could inadvertently delete the pointer, so the implementation above is considered safest (the destructor can also be declared private or protected to alleviate that problem).

The Singleton Pattern


The singleton pattern11 l.jpg

  • The object ( programmer from having any control over the lifetime of the object. static Singleton s) should be stored privately.

  • You provide access through public member functions. Here, instance( ) produces a reference to the Singleton object. The rest of the interface (getValue( ) and setValue( )) is the regular class interface.

The Singleton Pattern


Decoupling event handling with command l.jpg

  • Common task programmer from having any control over the lifetime of the object. : to separate event handling from “normal” computation thread of the application.

  • Use: to make sure event handling and the normal computation task are separated so that they can each reside in a separate execution thread for concurrent processing.

  • Implementation example: C10:MulticastCommand.cpp

  • To avoid coupling of code using the Command pattern. Each “normal” operation must periodically call a function to check the state of the events, but with the Command pattern these normal operations don’t need to know anything about what they are checking, and thus are decoupled from the event-handling code.

Decoupling Event Handling with Command


Decoupling event handling with command13 l.jpg

int main() { programmer from having any control over the lifetime of the object.

// Randomize for firing button click event randomly.

srand(time(0));

// Declare event generators

Button b1("Button 1"), b2("Button 2"), b3("Button 3");

// Declare event handlers

CheckButton cb1(b1), cb2(b2), cb3(b3);

// Add event handlers to the TaskRunner’s list.

TaskRunner::add(cb1);TaskRunner::add(cb2);TaskRunner::add(cb3);

// start the loop to perform “normal” computational work.

cout << "Control-C to exit" << endl;

while(true) {

procedure1();procedure2();procedure3();

// events will be checked and processed within the procedures

// while they perform the “normal” computational work.

}

} ///:~

Decoupling Event Handling with Command


Decoupling event handling with command14 l.jpg

// The procedures programmer from having any control over the lifetime of the object. to perform the “normal” computational work.

// Theseneed to be occasionally "interrupted" in order to

// check the state of the buttons or other events:

void procedure1() {

// Perform procedure1 operations here.

// ...

TaskRunner::run(); // Check all events

}

void procedure2() {

// Perform procedure2 operations here.

// ...

TaskRunner::run(); // Check all events

}

void procedure3() {

// Perform procedure3 operations here.

// ...

TaskRunner::run(); // Check all events

}

Decoupling Event Handling with Command


Decoupling event handling with command15 l.jpg

  • The event generators are Button b1, b2, b3; programmer from having any control over the lifetime of the object.

  • The event handlers are CheckButton cb1, cb2, cb3;

  • All event handlers are added to TaskRunner’s list.

  • The main loop starts the procedures to perform the “normal” computational work.

  • The procedures will run the TaskRunner patriotically to check and process events.

  • The procedures knows how to perform “normal” computational work, but does not know anything about how the events are generated, checked or processed, therefore decoupled from event handling.

Decoupling Event Handling with Command


Review command pattern l.jpg

  • Common task programmer from having any control over the lifetime of the object. : wrapping a function in an object => object-oriented command.

  • AKS: functor, an object representing a function (event handler)

  • Use: commands can be created, saved and passed around as objects with the functions (handlers)encapsulated.

  • Implementation example:

  • class Command {

  • public: virtual void execute() = 0; // can be any appropriate name

  • };

  • class CommandList{// An object that holds commands:

  •   vector<Command*> commands;

  • public:

  •   void add(Command* c) { commands.push_back(c); }

  •   void run() {

  •     vector<Command*>::iterator it = commands.begin();

  •     while(it != commands.end()) (*it++)->execute();

  •   }

  • };

Review: Command Pattern


Decoupling event handling with command17 l.jpg

class Task { programmer from having any control over the lifetime of the object.

public: virtual void operation() = 0;

};

class TaskRunner {

static vector<Task*> tasks;

TaskRunner() {} // Make it a Singleton by privatized the constructors

TaskRunner& operator=(TaskRunner&); // Disallowed

TaskRunner(const TaskRunner&); // Disallowed

static TaskRunner tr; // the single instance of the class

public:

static void add(Task& t) { tasks.push_back(&t); }

static void run() {

vector<Task*>::iterator it = tasks.begin();

while(it != tasks.end())(*it++)->operation();

}

};

Decoupling Event Handling with Command


Decoupling event handling with command18 l.jpg

// programmer from having any control over the lifetime of the object. Declare all static objects for later reference

TaskRunner TaskRunner::tr;

vector<Task*> TaskRunner::tasks;

class EventSimulator {

clock_t creation;

clock_t delay;

public:

EventSimulator() : creation(clock()) {

delay = CLOCKS_PER_SEC/4 * (rand() % 20 + 1);

cout << "delay = " << delay << endl;

}

bool fired() {

return clock() > creation + delay;

}

};

Decoupling Event Handling with Command


Decoupling event handling with command19 l.jpg

// Something that can produce asynchronous events: programmer from having any control over the lifetime of the object.

class Button {

bool pressed;

string id;

EventSimulator e; // For demonstration

public:

Button(string name) : pressed(false), id(name) {}

void press() { pressed = true; }

bool isPressed() {

if(e.fired()) press(); // Simulate the event

return pressed;

}

friend ostream&

operator<<(ostream& os, const Button& b) {

return os << b.id;

}

};

Decoupling Event Handling with Command


Decoupling event handling with command20 l.jpg

// The Command object programmer from having any control over the lifetime of the object.

class CheckButton : public Task {

Button& button;

bool handled;

public:

CheckButton(Button & b) : button(b), handled(false) {}

void operation() {

if(button.isPressed() && !handled) {

cout << button << " pressed" << endl;

handled = true;

}

}

};

Decoupling Event Handling with Command


Decoupling event handling with command21 l.jpg

  • The event handlers are defined as Command objects (functors) following the Command pattern. This is an object-oriented representation of event handlers.

  • The Command class is Task here.

  • CheckButtons are event handlers implementing the Task/Command.

  • The CommandList class is TaskRunner here.

  • All event handlers are added to TaskRunner’s list.

  • TaskRunner is a Signleton, we only need one TaskRunner.

  • When TaskRunner runs, it invokes “operation” for all CheckButtons (i.e. the event handlers.)

Decoupling Event Handling with Command


Decoupling event handling with command22 l.jpg

  • EventSimulator (functors) following the Command pattern. This is an object-oriented representation of event handlers. creates a random delay time, and changes fired() from returning false to true when the delay time has passed (“event has been fired”).

  • EventSimulator objects are used inside Buttons to simulate the act of a user event occurring at some unpredictable time.

  • TaskRunner is run periodically by all the “normal” code in the program (procedure1( ), procedure2( ) and procedure3( )).

Decoupling Event Handling with Command


ad