380 likes | 568 Views
Where Do Surrogates Fit into This Proxy Pattern Observer Pattern Visitor Pattern By Kurt Rehwinkel. Where Do Surrogates Fit into This. Introduction – What is a surrogate?
E N D
Where Do Surrogates Fit into ThisProxy PatternObserver PatternVisitor PatternByKurt Rehwinkel
Where Do Surrogates Fit into This • Introduction – What is a surrogate? • Webster’s Dictionary defines it as “one appointed to act in place of another”. The general context is that of a lawyer who represents a client before a court. • A more general concept is to consider a surrogate as someone or something that performs a process or task that is unable or unwilling to be performed by another. • Garbage collector, postal service, etc. • From the software perspective, surrogates can be thought of as “helper” type classes. These patterns provide valuable services by allowing aspects of a design to vary based on the needs of the software. These varying aspects include such things as interfaces, implementations, structures, responsibilities, etc. (Patterns 30)
Where Do Surrogates Fit into This • Things to consider when selecting Surrogates: • The requirements of the design may be such that multiple surrogate patterns should be implemented to obtain the cleanest design solution. In the file system example, the COMPOSITE pattern served as a solution when considering files and folders/directories. However, the PROXY served as a better solution when implementing symbolic links. • One or more additional surrogate patterns may be required in the implementation in support of the software design. In the file system example, the OBSERVER pattern was used to notify all proxies when a file was deleted to prevent “dangling” pointers.
Where Do Surrogates Fit into This • Working with base classes: • As a design evolves and the implementation develops, there is a tendency to treat a base class as a dumping ground for additional capability. This results in base classes that are tough to understand, cumbersome maintain, and difficult to implement. • The author makes the assertion that a primary goal in the design of bases classes is to provide a minimal set of operations allowing open-ended functionality. • If you find yourself adding functionality to a base class to support a single subclass, perhaps a pattern is a desirable alternative.
Where Do Surrogates Fit into This • Using multiple surrogate patterns: • Some designs may result in multiple patterns being implemented in classes that are interdependent. • These associations are result in “dense” composition of patterns. Having dense compositions can result in “profound” code (good stuff in a small space). • However, care must be taken to ensure that the desired patterns do not get lost after implemented.
Where Do Surrogates Fit into This • Reviewing surrogate usage: • Before adding functionality to base classes in the design software, consider surrogate patterns as a better alternative. • Use multiple surrogate patterns as needed to support the software design. This can serve to generate significant code in a small space. • Be careful to ensure that software patterns do not get lost after it has been implemented (can happen in “dense” composition patterns).
Proxy Pattern • Intent • Provide a surrogate or placeholder for another object to control access to it • Other Names • Surrogate
Proxy Pattern: Applicability • Forms of the proxy pattern: • Remote proxy – Provides a local representative for an object in a different address space. • Virtual Proxy – Creates expensive objects on demand. • Protection Proxy – Controls access to the original object. • Smart References – Additional functionality pointers. • Smart Pointers • Initial loading of persistent objects. • Object locking.
Proxy Pattern: Participants • Proxy • Maintains a reference to the real subject. • Provide identical interface to Subject so the Proxy can be substituted. • Controls access to the real subject and may be responsible for creating and deleting the real subject. • RealSubject • Defines the real object that the proxy represents. • Subject • Defines the common interface for RealSubject and Proxy so that the proxy to be used wherever a RealSubject is expected.
Proxy Pattern: Example Image* ImagePtr::operator->() { return LoadImage(); } Image& ImagePtr::operator*(){ return *LoadImage(); } To implement the Real Subject methods: ImagePtr image = ImagePtr(“aFile”); image->Draw(Point(50,100)); //(image.operator->())->Draw(Point(50,100)) class Image; class ImagePtr { public: ImagePtr(const char* file); virtual ~ImagePtr(); virtual Image* operator->(); virtual Image& operator*(); private: Image* _image; const char* _file; Image* LoadImage(); }; Image* ImagePtr::LoadImage(){ If (_image == 0 ) { _image = LoadAnImageFile(_file); } return _image; }
Proxy Pattern: Consequences • Each proxy introduces a level of indirection. This may result in hiding detail from the implementer. • A remote Proxy can hide the fact that object resides in a different address space. • A Virtual Proxy can perform optimizations such as creation on demand. • Protection Proxy and Smart References can allow additional housekeeping tasks when object is accessed. • Copy-On-Write • This hides optimization in which an object is not copied until it’s attributes are modified.
Proxy: Related Patterns • Adapter • Provides a different interface to an object. Since a proxy may deny request based on access, the interface is will be a subset. • Decorator • Similar implementation to proxy but has a different purpose. This adds responsibilities to an object rather than controlling access.
Observer Pattern • Intent • Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically • Also Known As • Dependents • Publish-Subscribe
Observer Pattern: Motivation • Partitioning a system into a collection of cooperating classes results in a need to maintain consistency between objects. • It is undesirable to achieve consistency via tightly coupled dependencies as this limits reusabiltiy.
Observer Pattern: Applicability • The following situations are prime examples for implementation of the observer pattern. • When an abstraction has two aspects with one dependant on the other. • When a change to one object requires changes to one or more other objects. • When an object needs to notify other objects but remain loosely coupled.
Observer Pattern: Participants • Subject • Maintains knowledge of the Observers. • Defines an interface for attaching and detaching Observer objects. • Observer • Defines an interface for objects to be notified when a subject changes.
Observer Pattern: Participants • ConcreteSubject • Maintains the state Subject. • Notifies the Observers via the Subject when its state changes. • ConcreteObserver • Maintains a reference to the ConcreteSubject. • Stores state that should stay consistent with the subject’s. • Implements the updating interface.
Observer Pattern: Consequences • Abstract coupling between Subject and Observer. • Support for broadcast (multicast) communication. • Unexpected updates caused by cascading updates to observers and their dependant objects.
Observer: Implementation • Mapping subjects to their observers. • Local storage is fast but may consume memory. Associative mapping saves space but requires is slower. • Observing multiple subjects by extending the update method in the Observer. • Who triggered the update? • The state-setting operations in the Subject determine when the notification occurs. • The client(s) are responsible for determining the appropriate time to notifiy.
Observer: Implementation • Dangling references to deleted subjects. • Subjects must notify Observers of the intent to be deleted. • Ensuring Subject state is “self-consistent” before notification. • Avoiding observer-specific update protocols. • Push Model – Information delivered as part of the notification. • Pull Model – Observers ask for details in response to the notification.
Observer: Implementation • Specifying modifications of interest explicitly. • State information is classified into “aspects” which are identified during notification. • Encapsulating complex update semantics through the implementation of a “Change-Manager”. • Takes responsibility of maintaining references to observers away from the Subject. • Defines a particular update strategy. • Updates all dependent observers at the request of a subject. • Combining the Subject and Observer. • May be useful when multiple inheritance not supported by language, both interfaces may reside in one class.
Observer: Related Patterns • Mediator • The ChangeManager encapsulates complex update semantics, thus acting as a mediator between the Subject and its Observers. • Singleton • ChangeManager may be unique and globally accessible.
Visitor Pattern • Intent • Lets you define a new operation without changing the classes on which they operate. • Motivation • Allows for increased functionality of a class(es) while streamlining base classes. As stated in the general section concerning surrogates, the author asserts that a primary goal of designs should be to ensure that base classes maintain a minimal set of operations. • Encapsulates common functionality in a class framework.
Visitor Pattern Motivation (cont) Visitors avoid type casting that is required by methods that pass base class pointers as arguments. The following code describes how a typical class could expand the functionality of an existing composite. Void MyAddition::execute( Base* basePtr) { if( dynamic_cast<ChildA*>(basePtr)){ // Perform task for child type A. } else if ( dynamic_cast<ChildB*>(basePtr)){ // Perform task for child type B. } else if( dynamic_cast<ChildC*>(basePtr)){ // Perform task for child type C. } }
Visitor Pattern: Applicability • The following situations are prime examples for implementation of the visitor pattern. • When an object structure contains many classes of objects with different interfaces and you want to perform functions on these objects that depend on their concrete classes. • When you want to keep related operations together by defining them in one class. • When the class structure rarely change but you need to define new operations on the structure.
Visitor Pattern: Participants • Visitor • Declares a Visit Operation for each class of Concrete Elements in the object structure. • Concrete Visitor • Implements each operation declared by Visitor. • Element • Defines an Accept operation that takes the visitor as an argument.
Visitor Pattern: Participants • Concrete Element • Implements an accept operation that takes the visitor as an argument. • Object Structure • Can enumerate its elements. • May provide a high level interface to all the visitor to visit its elements. • May either be a composite or a collection.
Visitor Pattern: Consequences • Makes adding new operations easier. • Collects related functionality. • Adding new Concrete Element classes is difficult. • Can “visit” across class types, unlike iterators. • Accumulates states as they visit elements. • May require breaking object encapsulation to support the implementation.
Visitor: Implementation • Implementation by the element classes. • The base element class contains an abstract method to accept the visitor. • Virtual void accept(Visitor&) = 0; • The concrete element classes implement the accept call in an identical manner. • void ElementA::accept(Visitor& v) {v.visit(this);} • void ElementB::accept(Visitor& v) {v.visit(this);}
Visitor: Implementation • Implementation of a single Visitor class can be used to implement simpler functionality. • A single visitor class may contain the set of methods for implementing all concrete element types. • void visit(ElementA*) ; • The client implements the single visitor and be passed into any element pointer type call. • Visitor v; • anElementPtr->visit(v);
Visitor: Implementation • Implementation of functionality for multiple visitor types is easy through inheritance. • A base visitor class contains an abstract method as a placeholder for each concrete element. • void visit(Element*)=0 ; • Each concrete visitor implements the functionality for all concrete elements. • void VisitorTypeA::visit(ElementA*) ; • void VisitorTypeA::visit(ElementB*) ; • void VisitorTypeB::visit(ElementA*); • void VisitorTypeB::visit(ElementB*);
Visitor: Implementation • The client implements the a instance of EACH visitor type passes into any element pointer type call. • VisitorTypeAvA; VisitorTypeBvB; • anElementPtr->visit(vA); • anElementPtr->visit(vB);
Visitor: Related Patterns • Composites • Visitors can be used to apply an operation over an object structure defined by the composite pattern. • Interpreter • Visitors may be applied to do the interpretation.