0% found this document useful (0 votes)
30 views23 pages

43 DesignPatterns-Part3

Uploaded by

Mato Nguyễn
Copyright
© © All Rights Reserved
0% found this document useful (0 votes)
30 views23 pages

43 DesignPatterns-Part3

Uploaded by

Mato Nguyễn
Copyright
© © All Rights Reserved
You are on page 1/ 23

Object-Oriented Software E ngineering

Practical Software Development using UML and Java

Design Patterns – Part 3


Sources:
Chapter 6: Using Design Patterns, and
Chapter 30 (parts) Designing the Logical Architecture with Patterns
Craig Larman’s Text: Applying UML and Patterns, Chaps: 16, 22, & 23.
6.6 3. The Observer Pattern (Gang of Four) 6

• This is another VERY popular design pattern.


• Context:
—When you have a two-way association is created between two
classes, the code for the classes becomes inseparable.
—If you want to reuse one class, then you also have to reuse the
other. There is a dependency.
• Problem:
—How do you reduce the interconnection between classes,
especially between classes that belong to different modules or
subsystems?
• Forces:
—You want to maximize the flexibility of the system to the
greatest extent possible

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 2


Observer
• Solution:
So, what do we do? We <<abstract>>
create an abstract class we «Observable» «interface»
* *
«Observer»
will call <<Observable>> addObserver
that maintains a collection notifyObservers update <<abstract>>
of <<Observer>> instances.

<<Observable>> class is «ConcreteObservable» «ConcreteObserver»


very simple; it merely has
a mechanism to add and
remove observers as well as a method, notifyObservers, that sends an update message to
each <<Observer>>. *

Any application class can declare itself to be a subclass of the <<Observable>> class.
In Java, we call these ‘listeners.’

So, the listener (concrete observable) implements addObserver and notifyObservers.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 3


Observer
The Observer Pattern (aka Dependents, Publish/Subscribe) is
a software design pattern in which an object, called the
subject (Observable here), maintains a list of its dependents,
called observers, and notifies them automatically of any state
changes, usually by calling one of their methods, update in the
previous slide.

Mainly used to implement distributed event handling systems.

Observer is also a key part in the familiar MVC architectural


pattern.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 4


The essence of the Observer Pattern is to “define a one
to many dependency between objects so that when one
object changes state, all of its dependents are notified
and updated automatically.
<<observable>>
earlier

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 5


Observer
• Solution: <<abstract>>
«Observable» «interface»
<<Observer>> is an interface, defining * *
«Observer»
only an abstract update method. addObserver
notifyObservers update <<abstract>>

Any class can thus be made to observe


an <<Observable>> by declaring that it «ConcreteObserver»
«ConcreteObservable»
implements the interface, and by
asking to be a member of the observer
list of the <<Observable>>.
Observable * * «interface»
Observer
The <<Observer>> can then expect a
call to its update method whenever the Observers are
<<Observable>> changes. notified when a new
Forecaster prediction is ready WeatherViewer

Using this pattern, the <<Observable>>


neither has to know the nature of the
number of classes that will be interested
in receiving an update messages nor
what they will do with this information.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 6


Observer
• Example:
Java has an Observer interface and an «Observable» * *
«interface»
«Observer»
Observable class. This is a specific addObserver
implementation of this pattern. notifyObservers update

Consider: a ‘forecast’ requires a lot of


«ConcreteObservable» «ConcreteObserver»
computations. Once done, it ‘notifies’
all interested instances.
Just a class…
Forecaster is thus an observable object. Observable * * «interface»
Observer
One observer object might be an interface
Observers are
object responsible for displaying weather notified when a new
forecast; another might be dependent on Forecaster prediction is ready WeatherViewer
weather information to plan a schedule..

Observer pattern in widely used to


structure software cleanly into relatively
independent modules. It is the basis of the
MVC architecture.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 7


6.7 4. The Delegation Pattern - 5
• Context:
—You are designing a method in a class
—You realize that another class has a method which provides the
required service
—Inheritance is not appropriate (e.g. because the ‘isa’ rule does
not apply
• Problem:
—How can you most effectively make use of a method that
already exists in the other class?
• Forces:
—You want to minimize development cost by reusing methods;
also reduce coupling between classes. Too, methods should be
near the data, and the existing class with the method might be
the more appropriate place for the existing method. So, …

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 8


Delegation
• Solution:

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, and not developing
our own version.

By neighboring class, we mean that the Delegate has an association with the Delegator class.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 9


Delegation
• Solution:
push()
Stack LinkedList {
list.addFirst();
push addFirst
}
pop addLast
isEmpty addAfter
removeFirst
removeLast
delete
isEmpty

Here we can see that Stack operations push, pop, and isEmpty can readily use
existing methods from Linked List class – addFirst, removeFirst, and isEmpty.

Thus, we have the above relationship.

Note the aggregate: This means, “has a.”

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 10


Delegation (continued)

Normally, the association already exists, and association


need only be unidirectional.

We may sometimes need to create a new association, if the


additional complexity doesn’t increase overall complexity
too much.

Kind of a ‘selective inheritance.’

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 11


Delegation
Antipatterns – This is not good:
• Overuse generalization and inherit the method that is to
be reused instead of creating a single method in the
«Delegator» class that does nothing other than call a
method in the «Delegate

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 12


6.8 5. The Adapter Pattern (Gang of Four)-6

• 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.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 13


Adapter Pattern (Internet)
The adapter pattern (often referred to as the wrapper pattern or simply
a wrapper) is a design pattern that translates one interface for a class into a
compatible interface.
An adapter allows classes to work together that normally could not because of
incompatible interfaces, by providing its interface to clients while using the
original interface.
The adapter translates calls to its interface into calls to the original interface,
and the amount of code necessary to do this is typically small.

There are two types of adapter patterns:


Object Adapter pattern and
Class Adapter pattern.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 14


Object Adapter Pattern
In this type of adapter pattern, the adapter contains an
instance of the class it wraps (Adaptee) so it can call the
method, methodB(). In this situation, the adapter makes
calls to the instance of the Adaptor via adaptor.methodA(),
which invokes adaptee.methodB().

Above is The object adapter pattern expressed in UML. The


adapter hides the adaptee's interface from the client.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 15


Class Adapter Pattern
This type of adapter uses multiple polymorphic interfaces to achieve its goal.
The adapter is created by implementing or inheriting both the interface that is
expected and the interface that is pre-existing.
It is typical for the expected interface to be created as a pure interface class,
especially in languages such as Java that do not support multiple
inheritance.

Adaptor inherits the interface and


implements the interface (see method1()

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 16


Adapter – according to Larman: class Adapter
• Solution: polymorphicMethod()
{
«Superclass» return
adaptee.adaptedMethod();
polymorphicMethod }

«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)

The polymorphic methods of <<Adapter>> delegate to methods of <<Adaptee>>, and delegate


method in <<Adaptee>> may / may not have same name as delegating polymorphic method.
Anything else in <<Adapter>> will be unaware that it is indirectly using the facilities of an
instance of <<Adaptee>>.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 17


Adapter
Example: volume()
ThreeDShape {
return
volum adaptee.calcVolume();
e }

Sphere Torus TimsTorus


calcVolume
We want to create a hierarchy of three-dimensional shapes, and we’d like to use an existing
implementation of calcVolume in TimsTorus. (TimsTorus is already in its own hierarchy)
We cannot modify the code in TimsTorus because it is being used by others, and thus cannot
make it a subclass of ThreeDShape.
So, we develop Torus (an <<Adapter>>) such that its instances have a link to the instance of
TimsTorus and delegate all operations to TimsTorus.

Adapters are sometimes called Wrappers. Java wrapper classes Integer, Float, Double, etc
are adapters for the Java primitive types.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 18


6.12 7. The Proxy Pattern (Gang of Four)-4
• Context:
—Often, it is time-consuming and complicated to create instances of a
class (heavyweight classes).
—There is a time delay and a complex mechanism involved in
creating the object in memory. Large classes must be loaded from
a database to support usage.
• Problem:
—How to reduce the need to create instances of a heavyweight class?
—Other objects may need to refer to or use instances of heavyweight
classes.
—Many domain classes are heavyweight classes; also common for
the collection classes used to implement associations (like
ArrayList or Vector) to be heavyweight classes too.
—So, how can we reduce the need to create instances of heavyweight
classes and/or to load large numbers of them from a database or
server when not all of then will be needed?

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 19


• Forces:
—We want all the objects in a domain model to be available for programs
to use when they execute a system’s various responsibilities.
—It is also important for many objects to persist from run to run of the
same program and it is impractical for all the objects to be loaded into
memory when a program starts.
—It would be much better to do the programming as if all objects were
already loaded into memory.
- Some programmers concerned with loading and storing the objects
- Some programmers concerned with implementing the responsibilities of
the domain model.
• A proxy, in its most general form, is a class functioning as an interface to
something else.
• The proxy could interface to anything: a network connection, a large object in
memory, a file, or some other resource that is expensive or impossible to duplicate.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 20


In situations where multiple copies of a complex object must exist, the proxy
pattern can be adapted to incorporate the lightweight pattern in order
to reduce the application's memory footprint.
Typically, one instance of the complex object and multiple proxy objects are
created, all of which contain a reference to a single original complex object.
Any operations performed on the proxies are forwarded to the original object.
Once all instances of the proxy are out of scope, the complex object's memory
may be deallocated.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 21


Proxy
«interface»
• Solution: «ClassIF»

* * «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.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 22


Proxy - Example
«interface» The list elements will
ListI be loaded into local
Example: F memory only when
needed.
ListProxy PersistentList

«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.

© Lethbridge/Laganière 2001 Chapter 6: Using design patterns 23

You might also like