55.DesignPatterns

advertisement
Object-Oriented Software Engineering
Practical Software Development using UML and Java
Chapter 6:
Using Design Patterns
Part 1
Preview:
• Want to look at more class diagrams – static.
• But we want to look at recurring groupings of classes
that are regularly used to address common
problems.
• Want to take advantage of experiences of others and
create a better, more resilient design.
• Want to use
patterns that assist us in separating concerns (abstractionoccurrence, observer, player-role);
patterns used to better create class hierarchies of instances;
patterns in which one method simply calls another method
in another class (have you seen this??);
patterns where you use delegation to gain access to facilites
in one or more other classes (Adaptor, Façade,
Proxy);
patterns that help protect other objects from unanticipated access
(immutable and read-only interfaces).
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
2
6.1 Introduction to Patterns
The recurring aspects of designs are called design patterns.
•  A pattern is the outline of a reusable solution to a general
problem encountered in a particular context
• Many of them have been systematically documented for all software
developers to use
• A good pattern should
—Be as general as possible
—Contain a solution that has been proven to effectively solve
the problem in the indicated context.
Studying patterns is an effective way to learn from the experience of
others
We will only look at a few.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
3
Pattern description
Context:
• The general situation in which the pattern applies
Problem:
—A short sentence or two raising the main difficulty.
Forces:
• The issues or concerns to consider when solving the problem
Solution:
• The recommended way to solve the problem in the given context.
—‘to balance the forces’
Antipatterns: (Optional)
• Solutions that are inferior or do not work in this context.
Related patterns: (Optional)
• Patterns that are similar to this pattern.
References:
• Who developed or inspired the pattern.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
4
Remember: our patterns define a relation between
a certain context
a problem
a solution
Patterns represent well-known knowledge
Really documents common practice
Patterns should be in the public domain
Patterns need to be written for the public good.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
5
6.2 The Abstraction-Occurrence Pattern
• Context:
— Often found in class diagrams that form part of the system
domain model.
—Often in a domain model you find a set of related objects
(occurrences).
—The members of such a set share common information but also
differ from each other in important ways. (Sports cars ….)
• Problem:
—What is the best way to represent such sets of occurrences in a
class diagram? Use the commonality, yet represent the
differences!
• Forces:
—You want to represent the members of each set of occurrences
without duplicating the common information.
- Cannot have this!
—Want to maximize the flexibility of the system too.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
6
Abstraction-Occurrence
• Solution:
«Abstraction»
Remember (Java): an
Interface can have
NO implementations;
may at most have
constants;
Abstract Class has at
least one abstract
method; can have
declarations.
TVSeries
*
*
seriesName
producer
Title
name
author
isbn
publicationDate
libOfCongress
«Occurrence»
Episode
number
title
storySynopsis
*
LibraryItem
barCodeNumber
Note: create an abstraction containing common data to all occurrences.
This is the “abstraction”. Then create the “occurrence” class that represents instances
(occurrences) of the abstraction. Realtionship is 1:*
ForeignSportsCar { CarMake; CountryofOrigin…} Auto { Model, Style, Cost..}
Note (as we shall see) this is not inheritance.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
7
Abstraction-Occurrence
Antipatterns:
LibraryItem
nam e
author
isb n
pub licatio nDate
lib OfCo ngres s
barCod eNumbe r
Single class: Bad because
info would have to be
duplicated in each
occurrence – and same
info would be in each
occurrence!
© Lethbridge/Laganière 2001
LibraryItem
Title
nam e
author
isb n
pub licatio nDate
lib OfCo ngres s
nam e
author
isb n
pub licatio nDate
lib OfCo ngres s
barCod eNumbe r
LibraryItem
GulliversTravels
MobyDick
Here, separate subclass for each title.
All other information would have to be
duplicated in each instance.
Also, want to be able to add new books
without programming new classes!
barCod eNumbe r
Problem here is making the
abstract class a super class
of the occurrence.
Attributes would be
inherited, of course, but
data would be lost! We’d
have to fill in name, author
… for each occurrence!
Chapter 6: Using design patterns
8
Abstraction-Occurrence
Square variant
ScheduledTrain
*
number
date
*
*
ScheduledLeg
*
scheduledDepTime
scheduledArrTime
origin
*
SpecificTrain
*
SpecificLeg
actualDepTime
actualArrTime
destination
Station
All we are saying here is that if the abstraction itself is an aggregate
(note ScheduledTrain and ScheduledLeg) the occurrences also are usually
aggregates (SpecificTrain; SpecificLeg). Read more on this on your own.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
9
6.3 The General Hierarchy Pattern
• Context: —Occurs in MANY class diagrams.
—Objects in a hierarchy can have one or more objects above them
(superiors), and one or more objects below them (subordinates).
—Some objects cannot have any subordinates
• Problem:
—How do you represent a hierarchy of objects, in which some
objects cannot have subordinates?
• Forces:
—You want a flexible way of representing the hierarchy
- that prevents certain objects from having subordinates
- yet, where all the objects have many common properties and
operations
• Main Thought: All hierarchies are NOT necessarily inheritance
hierarchies!!!!
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
10
General Hierarchy
«Node»
• Solution:
*
«subordinate»
0..1
«NonSuperiorNode»
Employee *
supervises
«SuperiorNode»
FileSystemItem *
0..1
Secretary
Technician
Manager
contains
0..1
File
Directory
Create an abstract <<Node>> class that represents features possessed by all – like on that each
node can have a superior class.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
11
General Hierarchy
«Node»
• Solution:
*
«subordinate»
0..1
«NonSuperiorNode»
Employee *
supervises
«SuperiorNode»
FileSystemItem *
0..1
Secretary
Technician
Manager
contains
0..1
File
Directory
Then create at least two subclasses of the <<Node>> class. One of the subclasses <<SuperiorNode>>
must be linked by a <<subordinates>> association to the superclass; whereas at least one
subclass <<NonSuperiorNode>> must not be. The subordinates of <<SuperiorNode>> can thus
be instances of either SuperiorNode or NonSuperiorNode.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
12
General Hierarchy
«Node»
• Solution:
*
«subordinate»
0..1
«NonSuperiorNode»
Employee *
supervises
«SuperiorNode»
FileSystemItem *
0..1
Secretary
Technician
Manager
contains
0..1
File
Directory
The multiplicity of the <<subordinates>> association can be optional-to-many or many-to-many.
If many-to-many, then the hierarchy of instances becomes a lattice, in which a node can have many
superiors. The ‘optional’ allows for the case of the top node in the hierarchy, which has no superiors.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
13
General Hierarchy
• Examples:
Employee *
supervises
FileSystemItem *
0..1
Secretary
Technician
Manager
contains
0..1
File
Directory
Here, we have three types of employees in the organization: only managers can supervise subordinates. So,
All are employees and inherit from Employee class. An employee has zero or one managers (manager - as
an employee - may not have a manager). Manager may supervise many
employees. Secretaries and Technicians cannot have subordinates; manager can.
In the second examle, FileSystemItem is the superiorclass. File and Directory inherit from FileSystemItem.
Only Directories can contain other file system objects, and this is described by the * relationship – a
directory may contain any number of file system items, but a file system item is contained in 0 or 1
directory. Where this is powerful is that both the File and the Directory inherit from FileSystemItem, yet
one of the subordinates can contain instances of the superclass.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
14
General Hierarchy
Antipattern:
Recording
VideoRecoding
MusicVideo
AudioRecording
JazzRecording ClassicalRecording
BluesRecording RockRecording
Don’t fall into the trap of thinking a hierarchy of categories is necessarily a
hierarchy of classes!
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
15
6.4 The Player-Role Pattern
• Context: (More issues with Generalization…)
— An object may play different roles in different
contexts. Want to model class diagrams for this!
—Pattern used to solving modelling problems when
you are drawing many different types of class
diagrams.
—A role is a particular set of properties associated with
an object in a particular context.
• Problem:
—How do you best model players and roles so that a
player can change roles or possess multiple roles?
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
16
Player-Role
• Forces:
—It is desirable to improve encapsulation by capturing the
information associated with each separate role in a class.
—You want to avoid multiple inheritance.
—You cannot allow an instance to change class
• Solution:
«Player»
1
*
«AbstractRole»
Create a <<Player>> class to represent the
object that plays different roles. Create an
association from this class to an abstract
<<Role>> class, which is a superset of all
«Role1»
possible roles. The subclasses of this
<<Role>> class encapsulate all the
properties and behaviors associated with the
different roles. (Recall abstract classes can
have ‘some’ behaviors and can have declarations).
© Lethbridge/Laganière 2001
«Role2»
Chapter 6: Using design patterns
17
Player-Role
«Player»
1
*
«AbstractRole»
«Role1»
«Role2»
If the <<Player>> can only play one role at a time, the multiplicity between
<<Player>> and <<Role>> is one-to-one; otherwise it will be one-to-many.
<<Role>> can be an Interface – but normally a Role contains a mechanism inherited
by its subclasses, allowing them to access information about the <<Player>>.
So make <<Role>> an interface only if this mechanism is not needed (cannot
implement methods or have declarations in an interface (other than constants).
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
18
Player-Role
Example 1:
Note the two roles of animals: role based on: type of food, habitat.
Idea behind these roles is that an animal may have to switch from
one role to another. We don’t want to have to model this situation by
destroying one class and creating another class – or opposite.
Could make habitat an attribute of HabitatRole and omit two subclasses.
But then we lose the advantage of polymorphism for any operations that
would differ in Aquatic Animal and Land Animal.
Animal
ty peOfFood
Carnivore
Herbivore
Omnivore
0..2
HabitatRole
habitat
AquaticAnimal
LandAnimal
Here, an animal may have a varying number of roles: aquatic, land-based or both.
Can also have used a role to capture whether animal is carnivore, herbivore or omnivore.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
19
Player-Role
Example 2:
AttendanceRole
Student
LevelRole
attendanc e
FullTimeStudent PartTimeStudent
level
GraduateStudent
UndergraduateStudent
Here, we have two separate <Role>> superclasses. In one, student is characterized by his/her
attendance status and by whether or not s/he is a graduate student (or not)..
Both of these statuses can changed during the life of the Student object. This pattern, therefore,
makes it possible to represent a full or part time graduate or undergraduate student.
Here, modeling Student in this manner is much better and flexible. It supports polymorphism
and is responsive to any changes in role the Student might take, whether these changes be
in attendance or in level (or both).
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
20
Player-Role
Confusing in spots:
All this can be confusing. For example, it appears that the playerrole could be an abstraction-observer pattern. Certainly has
similar structure.
Player has many roles associated with it just like the abstraction has
many occurrences.
But there is a major difference:
In the Abstraction-Occurrence pattern, an abstraction is …
abstract, while its occurrences ten to be real-work things, such as
copies of books, or autos
In the Player-Role pattern, just the opposite is true, where
the player is normally the real-world entity (e.g. a person) while its
roles are abstractions.
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
21
6.5 The Singleton Pattern
• 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
22
Singleton
• Solution:
«Singleton»
theInstance
getInstance
Have a private class variable,
possibly called, ‘theInstance.’
This stores the instance.
Company
Then have a public class method
(static method) possibly called,
‘getInstance.’
theCompany
if (theCompany==null)
theCompany= new Company();
Company «private»
getInstance
return theCompany;
First time method is called, it creates
a single instance and stores it in
theInstance.. Subsequent calls simply
return theInstance.
A private Constructor, which ensures
no other class will be able to create
an instance of the singleton class is
needed.
© Lethbridge/Laganière 2001
Here, Company class may embody several
important characteristics of the Company
(operations and attributes).
The public class method getInstance() makes
this instance globally accessible.
Note: effectively, the Singleton instance is
effectively a global variable. Minimize these.
Chapter 6: Using design patterns
23
6.6 The Observer Pattern
• Second in the gang-of-four patterns (Singleton was the first)
• This is another VERY popular one.
• 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
24
Observer
• Solution:
So, what do we do? We
create an abstract class we
will call <<Observable>>
that maintains a collection
of <<Observer>> instances.
«Observable»
*
addObserver
notifyObservers
*
«interface»
«Observer»
update
<<Observable>> class is
«ConcreteObserver»
«ConcreteObservable»
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.’
© Lethbridge/Laganière 2001
Chapter 6: Using design patterns
25
Observer
• Solution:
<<Observer>> is an interface, defining
only an abstract update method.
Any class can thus be made to observe
an <<Observable>> by declaring that it
implements the interface, and by asking
to be a member of the observer list of
the <<Observable>>.
«Observable»
*
*
addObserver
notifyObservers
update
«ConcreteObservable»
Observable
«interface»
«Observer»
«ConcreteObserver»
*
* «interface»
Observer
The <<Observer>> can then expect a
call to its update method whenever the
<<Observable>> changes.
Forecaster
Observers are
notified when a new
prediction is ready
WeatherView er
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
26
Observer
• Example:
Java has an Observer interface and an
Observable class. This is a specific
implementation of this pattern.
«Observable»
*
*
addObserver
notifyObservers
Consider: a ‘forecast’ requires a lot of
computations. Once done, it ‘notifies’
all interested instances.
«interface»
«Observer»
update
«ConcreteObservable»
«ConcreteObserver»
Just a class…
Forecaster is thus an observable object.
Observable
*
* «interface»
Observer
One observer object might be an interface
object responsible for displaying weather
forecast; another might be dependent on
weather information to plan a schedule..
Forecaster
Observers are
notified when a new
prediction is ready
WeatherView er
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
27
Download