Where Do Surrogates Fit into This Proxy Pattern Observer Pattern Visitor Pattern By Kurt Rehwinkel
description
Transcript of Where Do Surrogates Fit into This Proxy Pattern Observer Pattern Visitor Pattern By Kurt Rehwinkel
Where Do Surrogates Fit into This
Proxy PatternObserver Pattern
Visitor Pattern
ByKurt 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: Structure
Proxy Pattern: Example
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;
}
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))
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: Structure
Observer Pattern: Collaborations
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: Structure
Visitor Pattern: Collaborations
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.
VisitorTypeA vA; VisitorTypeB vB; 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.