1 / 42

Design Patterns

Design Patterns. Structural Patterns. Adapter. Convert the interface of a class into another interface clients expect Adapter lets classes work together that couldn't otherwise because of incompatible interfaces Use the Adapter pattern when:

Download Presentation

Design Patterns

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. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Design Patterns Structural Patterns

  2. Adapter • Convert the interface of a class into another interface clients expect • Adapter lets classes work together that couldn't otherwise because of incompatible interfaces • Use the Adapter pattern when: • you want to use an existing class and its interface does not match the one you need • you need to use several existing subclasses, but it's impractical to adapt their interface by subclassing everyone. An object adapter can adapt the interface of its parent class

  3. Adapter

  4. Bridge • Decouple an abstraction from its implementation so that the two can vary independently • Use the Bridge pattern when: • you want run-time binding of the implementation • you want to share an implementation among multiple objects

  5. Bridge

  6. Composite • Compose objects into tree structures to represent whole-part hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly • Use this pattern whenever you have "composites that contain components, each of which could be a composite".

  7. Composite

  8. Decorator • Attach additional responsibilities to an object dynamically • Decorators provide a flexible alternative to subclassing for extending functionality

  9. Problems • Several classes with a similar operation (method), but different behavior. • We want to use many combinations of these behaviors

  10. Example - Automated Hospital • People come to the reception with problems • They describe their problems • A special doctoRobot is created that is specialized to treat their special situations.

  11. Automated Hospital - Solution 1

  12. Problems with solution-1 • Sometimes we don’t have multiple inheritance. • Even if we have, if is problematic, and bad design. • 2n possible classes to create before compilation.

  13. A Better idea: Use Decorator

  14. Decorator in our case

  15. Code Example Widget* aWidget = new BorderDecorator( new HorScrollDecorator( new VerScrollDecorator( new TextWidget( 80, 24 )))); aWidget->draw(); Stream* aStream = new CompressingStream( new ASCII7Stream( new FileStream( "fileName.dat" ))); aStream->putString( "Hello world" );

  16. Benefits • Flexible • Don’t have to foresee all combinations • Little objects Possible problems • Performance • Decorators are not necessarily always cummutative(surgeon and Anastasiolic)

  17. Facade • Provide a unified interface to a set of interfaces in a subsystem • Facade defines a higher-level interface that makes the subsystem easier to use • Create a class that is the interface to the subsystem • Clients interface with the Facade class to deal with the subsystem • It hides the implementation of the subsystem from clients • It promotes weak coupling between the subsystems and its clients • It does not prevent clients from using subsystems class, should it?

  18. Facade

  19. Flyweight • Use sharing to support large numbers of fine-grained objects efficiently • The pattern can be used when: • The program uses a large number of objects and • Storage cost are high because of the sheer quantity of objects and • The program does not use object identity (==)

  20. Flyweight

  21. Proxy • Provide a surrogate or placeholder for another object to control access to it. • The proxy has the same interface as the original object • Virtual Proxy: • Creates/accesses expensive objects on demand • You may wish to delay creating an expensive object until it is really accessed • It may be too expensive to keep entire state of the object in memory at one time

  22. Protection Proxy • Provides different objects different level of access to original object • Cache Proxy (Server Proxy) • Multiple local clients can share results from expensive operations: remote accesses or long computations • Firewall Proxy • Protect local clients from outside world

  23. Proxy

  24. Dynamics

  25. Reference Counting • Don’t bother to make a copy of something until you really need one:Be Lazy ?! • Use someone else’s copy as long as you can get away with it. Class String { … }; String s1 = “Hello”; String s2=s1; cout << s1; cout << s1 + s2; S2.convertToUpperCase();

  26. Reference Counting • Copying the string contents in every • Assignment, • Argument passing, and • Function returning value • Can be both • Expensive, and • Unnecessary!

  27. The basic String class class String { public: String(const char* value= “”); String(const String& rhs); String& operator=(const String& rhs); … private: char *date; };

  28. The common implementation String& String::operator=(const String& rhs) { if(this == &rhs) return * this; delete [] data; data = new char[strlen(rhs.data) + 1]; strcpy(data,rhs.data); return *this; }

  29. Using the String class String a,b,c,d,e; a=b=c=d=e=“Hello” String A Hello\0 String B Hello\0 String C Hello\0 String D Hello\0 String E Hello\0

  30. The Idea Behind Reference Counting String A Reference String B String C 5 Hello\0 String D String E

  31. Implement The Reference Counting class String{ private: struct StringRef{ int refCount; char *data; StringRef(const char *initValue); ~StringRef(); }; StringRef *value; public: String(const char* value= “”); String(const String& rhs); String& operator=(const String& rhs); … };

  32. StringRef class implementation String::StringRef::StringRef(const char* initVal) : refCount(1) { data = new char[strlen(initVal) + 1]; strcpy(data,initVal); } String::StringRef::~StringRef() { delete []data; }

  33. String class implementation String::String(const char *initVal) : value(new StringRef(initVal)) {} String::String(const String& rhs) : value(rhs.value) { ++value->refCount; } String::~String() { if(--value->refCount == 0) delete value; }

  34. String class implementation String& String::operator=(const String& rhs) { if (value == rhs.value) return *this; if (--vaule->refCount == 0) delete value; value = rhs.value; ++value->refCount; return *this; }

  35. Using the String class String s1(“More Effective c++”); String s2(“More Effective c++”); String s3=s2; String s4; S4=s3; StringRef s1 More Effective c++\0 1 s2 s3 More Effective c++\0 3 s4

  36. Copy on Write Class String { … public: char operator[](int index) const; char& operator[](int index); … }; char String::operator[](int index) const { return value->data[index]; }

  37. Copy on Write char& String::operator[](int index) { if(value->refCount > 1){ --value->refCount; value = new StringRef(value->data); } return value->data[index]; } … String s1; const String s2; … cout << s1 << s2; s1[5] = ‘x’;

  38. Distinguishing Reads from Writes • Reading a reference counting is cheap • Writing require splitting off a new copy String s = “H. Simpson”; cout << s[5]; S[5] = ‘I’;

  39. Distinguishing Reads from Writes via operator[] class String{ public: class CharProxy{ public: CharProxy(String& str,int index); CharProxy& operator=(const CharProxy& rhs); CharProxy& opeartor=(char c); operator char() const; private: String& theString; int charIndex; }; const CharProxy operator[](int index) const; CharProxy operator[](int index); … friend class CharProxy; private: struct StringRef{…}; StringRef *value; };

  40. Distinguishing Reads from Writes via operator[] const String::CharProxy String::operator[](int index) const { return CharProxy(const_cast<String&>(*this),index); } String::CharProxy String::operator[](int index) { return CharProxy(*this,index); } String::CharProxy::CharProxy(String& str,int index) : theString(str),charIndex(index){} String::CharProxy::operator char() const { return theString.value->data[charIndex]; }

  41. Distinguishing Reads from Writes via operator[] String::CharProxy& String::CharProxy::operator=(const CharProxy& rhs) { if(theString.value->reCount > 1) theString.value = new StringRef(theString.value->data); theString.value->data[charIndex] = rhs.theString.value->data[charIndex]; return *this; } String::CharProxy& String::CharProxy::operator=(char c) { if(theString.value->reCount > 1) theString.value = new StringRef(theString.value->data); theString.value->data[charIndex] = c; return *this; }

  42. Using the proxy class String s1,s2; … cout << s1[5]; s1[5] = ‘x’; s1[3] = s2[8];

More Related