Professional Documents
Culture Documents
Design Patterns - Details: Gang of Four (Gof) Patterns Grasp Patterns More
Design Patterns - Details: Gang of Four (Gof) Patterns Grasp Patterns More
Part 2
Singleton
Observer
Delegation
Adaptor
Façade
Proxy
• Context:
—It is very common to find classes for which only one
instance should exist (singleton)
- Examples: a Main Window; Company or University class.
• Problem:
—How do you ensure that it is never possible to create
more than one instance of a singleton class?
• Forces:
—The use of a public constructor cannot guarantee that
no more than one instance will be created.
—The singleton instance must also be accessible to all
classes that require it
© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 7
Singleton
«Singleton»
• Solution: theInstance
getInstance
Have a private class variable,
possibly called, ‘theInstance.’
This stores the instance.
Company
if (theCompany==null)
Then have a public class method theCompany theCompany= new Company();
(static method) possibly called, Company «private»
‘getInstance.’ getInstance return theCompany;
First time method is called, it creates Here, Company class may embody several
Any application class can declare itself to be a subclass of the <<Observable>> class.
In Java, we call these ‘listeners.’
delegatingMethod()
«Delegator» «Delegate» {
delegate.method();
delegatingMethod method }
Create a method in a Delegator class that only calls a method in a neighboring Delegate class.
In this way, we are reusing the method for which Delegate has responsibility.
By neighboring class, we mean that the Delegate has an association with the Delegator class.
Here we can see that Stack operations push, pop, and isEmpty can readily use
existing methods from Linked List class – addFirst, addLast, and isEmpty.
• Context:
—You are building an inheritance hierarchy and want to
incorporate it into an existing class.
—The reused class is also often already part of its own
inheritance hierarchy.
• Problem:
—How to obtain the power of polymorphism when reusing a
class whose methods
- have the same function
- but not the same signature
as the other methods in the hierarchy?
• Forces:
—You do not have access to multiple inheritance or you do not
want to use it.
«Adapter» «Adaptee»
adaptedMethod
We don’t want to directly incorporate the reused class into our inheritance hierarchy.
Better: Use an <<Adapter>> class that is connected via association to the reused class. (Adaptee)
Adapters are sometimes called Wrappers. Java wrapper classes Integer, Float, Double, etc
are adapters for the Java primitive types.
• Context:
—Often, an application contains several complex packages.
—A programmer working with such packages has to manipulate
many different classes
• Problem:
—How do you simplify the view that programmers have of a
complex package?
• Forces:
—It is difficult for a programmer to understand and use an entire
subsystem
—If several different application classes call methods of the
complex package, then any modifications made to the package
will necessitate a complete review of all these classes.
• Here, the most common pattern of access is Façade, a GoF design pattern.
• We have a public façade object defining the services for the subsystem, and clients
collaborate with the façade, not internal subsystem components.
• The façade should not normally expose many low-level operations. Rather, it exposes
a small number of high-level operations – the coarse-grained services.
• A façade does not normally do its own work. Rather, it is consolidator or mediator to the
underlying subsystem objects, which do the work.
• The façade is a wrapper and single point of access into the ‘rules engine’ of a subsystem.
Below: The façade class abstracts Packages 1,2, and 3 from the rest of the
application.
Clients use the façade pattern to access resources from the packages.
They are going to ‘doStuff’ with the objects c1, c2, and c3
We create a special class called a <<Façade>>, which simplifies* the use of the package.
The Façade class simply contains a simplified set of public methods.
*
Result is the creation of a class containing the most often used / needed facilities in the
package. Thus other client elements desiring services of this complex
package can avail themselves of the Façade class, where it is likely what
services they want are simpler to acquire.
Since we are talking about a complex package, other clients that need some of the
complexities of the package can access these services as they normally would – via the
public interfaces of these other classes.
Some design elements, like subsystems, may need to interact with the airline system but
don’t want to be exposed to any changes that might be made to it (via dependencies).
So, we can define and Airline class to be a <<Façade>> that contains methods (access) to
the most important query and booking operations in other classes in the airline system.
Thus any dependency arising from this relation is only on the Façade class.
Here, above, via the Airline façade class, we have access to two other classes from other
likely complex packages
* * «Proxy» «HeavyWeight»
«Client»
Create a simpler version of the heavyweight class, which we call a Proxy, which has the same
interface as the heavyweight class so programmers can declare variables without caring about whether
the Proxy or its Heavyweight version will be put in the variable.
The Proxy object is really only a placeholder, and the operations in the Proxy delegate the operation to
the HeavyWeight.
If/when needed, the Proxy can obtain the real heavyweight object. Further, the proxy only needs to
obtain the heavyweight one time and thus make it available in memory to others who use the proxy.
Some proxies may have implementations of a limited number of operations that can be
performed without the effort of loading the Heavyweight object.
«interface»
Student
StudentProxy PersistentStudent
Here we have a variable that is to contain a List. This variable would, however, actually contain a
ListProxy, since it would be expensive to load an entire list of objects into memory, and the list might
not actually be needed. However, as soon as an operation accesses the list, the ListProxy might at
that point create an instance of PersistentList.
On the other hand, the ListProxy might be able to answer certain queries, such as the number of
elements in the list, without going to the effort of loading the PersistentList.
Imagine that the PersistentList is actually a list of students. These objects might also be
proxies – in this case, instances of StudentProxy. Again, instances of PersistentStudent
would only be loaded when necessary.