Lecture 09 Design Patterns
Download
Report
Transcript Lecture 09 Design Patterns
CS5103
Software Engineering
Lecture 09
Software Design and
Design Patterns
Last class
Sequence diagrams
Software architecture
2
Why? Higher level design of larger software
projects
Software architectural styles
Pipe and Filter
Layered
Repository
Today’s class
3
Software Design
Process
Factors
Measures
Design Patterns
Composite pattern
Factory pattern
Visitor pattern
Software Design Process
Software design is usually created in two stages
Architecture design
Detail design (component-level design)
4
Design patterns
Design classes
Design review
Other design issues
Refactoring
UI Design
Software Design Factors
Fundamental software design factors
5
Modularity
Abstraction
Information hiding
Component independence
Fault prevention and fault tolerance
Modularity and Abstraction
When we consider modular solutions to any
problems, many levels of abstraction can be posed
At the lower levels of abstraction, a more detailed
description of the solution is provided: class diagrams
Modularity hides details and facilitates evolvement
6
At the highest level of abstraction, a solution is stated in
broad terms of problem domain: architecture
Each component hides a design decision from the others
Component Independent
7
We strive in most designs to make the components
independent of one another, why?
We measure the degree of component
independence using two concepts
Low coupling
High cohesion
Coupling and Cohesion
Coupling
Two components are loosely coupled when they have some
dependence, but the interconnections among them are
weak
Two components are uncoupled when they have no
interconnections at all
Cohesion
8
Two components are highly coupled when there is a great
deal of dependence between them
A component is cohesive if the internal parts of the
component are related to each other and to its overall
purpose
Decoupling
Most difficult part in design: Need tradeoff
Consider the following case:
Online and offline bookstore components
Both need shopping cart checkout
9
Should we have a shopping cart checkout module for both
of them? Or have one, and let the two components to call
the module?
Consider potential changes on overall book discount policy
and specific book discount policy?
Solution for the dilemma: break the checkout module, still
not perfect
Fault defense & tolerance
Defensive design anticipates situations the might
lead to problems
Network Failure
Data corruption
Invalid user inputs
Tolerate runtime errors
10
Exception handling
Redundant components (distributed system or critical
software)
Timely error reporting
Criteria for Good Software Design
11
High-quality designs should have characteristics
that lead to quality products
Correct translation from the requirements specification
Ease of understanding
Ease of implementation
Ease of testing
Ease of modification
Criteria for Good Software Design
12
Architecture
Using suitable architectural styles or patterns
Loose-coupled components
Can be implemented in an evolutionary fashion
Classes at a suitable abstract level
Interfaces are clear and minimize the data
transfer
Design using a effective notation
Software Design Evaluation and
Validation
We check a design in two different ways
13
Validation: the design satisfies all requirements specified
by the customer
Verification: the characteristics (quality) of a good
design are incorporated
We use some techniques for helping us to perform
verification and validation
Measuring design quality
Design reviews
Measuring Software Design Quality
14
We check a design using a set of measures
Coupling
Cohesion
Complexity
Basic metrics: size
Depths of relations
Cyclomatic complexity
Design reviews
15
We check a design
Designers
Customers
Analysts
prospective users
Developers
Moderator leading the discussions
Secretary recording the issues
Design Patterns
Become popular due to a book
16
Design Patterns: Elements of Reusable ObjectOriented Software
Gang of Four: Gamma, Erich; Richard Helm,
Ralph Johnson, and John Vlissides
Provide solutions for common problems
in micro-design
Design Patterns Structure
Name
Problem solved
When to apply the pattern
Solution
17
Important to know for easier communication between
designers
Usually a class diagram segment (sometimes attributes
and operations)
Design Patterns
Structure Patterns
Creation Patterns
Factory
Behavioral Patterns
18
Composite
Visitor
Running Example
19
A Document Editor
Text and graphics can be freely mixed
Graphical user interface
Support different look-and-feel GUI styles
Traversal operations: spell checking
Composite Pattern: Example
A document is represented by structure
Primitive glyphs
20
Characters, circles, pictures
Lines: A sequence of glyphs
Columns: A sequence of Lines
Pages: A sequence of Columns
Documents: A sequence of Pages
Example of Hierarchical Document
21
Possible Designs?
Document
1
*
Page
Classes of Character, Circle, Pictures, lines,
Columns, pages, document
Composition relationship between classes
Not so good, why?
A lot of duplication:
1*
Column
1*
Line
1
*
Glyph
all classes has onClick, draw behavior
Difficult to add or remove levels in hierarchy
Character
22
Picture
Traverse/display operations need to change for
any change of the hierarchy
Alternate Designs
One class of Glyph
23
All elements are subclasses of Glyph
All elements uniformly present the same
interface
How to draw
Computing bounds
Mouse hit detection
…
Make extending the class easier
Logic Object Structure
24
Logic Object Structure
25
Composite Pattern
Applies to any hierarchy structure
Leaves and internal nodes have similar functionality
Pros:
Easy to add, remove new types
Clean interface
Cons:
26
Add corner cases
Enforce certain type of elements only have
certain types of children
Problem: Supporting look-and-feel
settings
Different look-and-feel standards
Appearance of scrollbars, menus, windows,
etc., set by the user
We want to support them all
27
For example: having classes MotifScrollBar
and WindowsScrollBar
Both are subclasses of ScrollBars
How should we create a new scrollbar in a
window?
Possible designs?
Terrible
ScrollBar sc = new WindowScrollBar();
Better, problems?
If (style==MOTIF){
sc = new MotifScrollBar();
}else{
sc = new WindowScrollBar();
}
28
Conditions for other UI elements: menus, etc.
Hard to add new styles
Factory Pattern
29
One method to create a look-and-feel dependent
object
Define a GUIFactory Class
One GUIFactory object for each look and feel
Create itself using conditions set by the user
Factory Pattern
30
Factory Pattern: factory design
abstract class GUIFactory{
abstract ScrollBar CreateScrollBar();
abstract Menu CreateMenu();
...
}
31
class MotifFactory extends GuiFactory{
ScrollBar CreateScrollBar(){
return new MotifScrollBar()
}
Menu createMenu(){
return new MotifMenu();
}
...
}
Factory Pattern: GUI code
GuiFactory factory;
if(style==MOTIF){
factory = new MotifFactory();
}else if(style==WINDOW){
factory = new WindowFactory();
}else{
...
}
ScrollBar bar = factory.createScrollBar();
Menu mn = factory.createMenu();
32
Factory Pattern
Applies to the object creation of a family of
classes
The factory can be changed at runtime
Pros & Cons
33
Lift the conditional creation of objects to the
creation of factories
Flexible for add new type of objects
Sometimes make the code more difficult to
understand
Spell Checking Problem
Considerations
Requires to traverse the document
Need to see every glyph in order
There maybe other analyses that require
traverse the document
Counting
34
words, Grammar checking
Possible design
class Glyph{…
void spellCheck(char[] curWord):
for(int i = 0; i<this.children.length; i++):
this.children[i].spellCheck(curWord);
if(this isa character):
if(this == space):
Util.SpellCheck(curWord); curWord.clear();
else:
curWord.append(this);
…}
35
Other Actions
36
Document Stats
counting words,
counting pictures,
counting lines, columns, pages)
Find a word
Change line-break rules
…
Now we have
A large number of similar methods
Code duplication always causes problems
37
All need to traverse the document
change the data structure of “children” from
array to list (better insertion and deletion)
Skip full-picture page to enhance
performance for word-related tasks
Solution
Visitor pattern
Decouple traverse process and action
Write traverse code only once
38
Each element in the hierarchy under traverse
has an “action” code
Visitor pattern basic design
class Glyph{…
void scan(Visitor v):
for(int i = 0; i<d.children.length; i++):
d.children[i].scan(v);
…}
We have different visitors: spellcheckVisitor,
documentStatVisitor, etc.
39
Solution
40
Code of SpellCheckVisitor
class SpellCheckVisitor extends Visitor{
char[] curWord = {};
void visitChar(Character c){
if(c==SPACE):
spellCheck(curWord);
curWord.clear();
else:
curWord.add(c);
}
}
41
Still have problems
42
How about counting all glyphs (including
picture, character, circle)?
Need to change visitPicture, visitCharacter,
and visitCircle?
Add visitGlyph
Add VisitGlyph
class Glyph{
…
scan(Visitor){
for each c in children:
v.visitGlyph(c)
c.Scan(v)
}
…
}
43
Code of CountGlyphVisitor
class CountGlyphVisitor extends Visitor{
int count = 0;
void visitGlyph(Glyph g){
if(g.children.length==0):
count++;
}
}
}
44
Summary of design patterns
Major aim: decoupling
pros:
more flexibility
less changes when modification is required
Cons:
45
not intuitive at the beginning, harder to read code, but
get easier when you are familiar with the pattern
Trouble for verifications and analysis (often not scalable
without a design pattern)
So it is rather popular!
Other useful design patterns
Observer
Facade
Factory method
Decorator
Bridge
See them in wiki pages or read the book
46
Design Patterns: Elements of Reusable Object-Oriented
Software
Today’s class
47
Software Design
Design process
Design factors
Design evaluation
Design Patterns
Composite pattern
Factory pattern
Visitor pattern
Next Class
48
Software Implementation: Versioning
Why versioning?
Versioning tools
CVS
SVN
GIT
Thanks!
49
A controversial pattern:
singleton pattern
Problem
50
How to make sure a class only has one object
File system
Windows manager
…
The class itself is made responsible for keeping
track of its instance. It can thus ensure that no
more than one instance is created. This is the
singleton pattern.
Singleton Pattern
Singleton
static uniqueInstance
singletonData
static Instance()
SingletonOp()
GetSingletonData()
return uniqueinstance
Singleton Pattern: code
class Singleton {
// Only one instance can ever be created.
public:
static Singleton Instance();
protected:
// Creation hidden inside Instance().
Singleton();
private:
Static Singleton _instance
}
// Cannot access directly.
Singleton Pattern: code
Singleton _instance;
Singleton Instance(){
if (_instance ==null) {
_instance=new Singleton;
}
Return _instance;
}
// Clients access the singleton
// exclusively via the Instance member
// function.
Singleton Pattern
Pros
54
Controls the number of instances (no need to
refer to another class)
Lazy initialization
Cons
Latent coupling between components and singleton
Singleton may have states: hard to test
Cannot extend singleton class
Terrible in multi-thread if not well implemented
View points
55
We love singletons (getting weaker and weaker in
the past 10 years)
Singletons are evil, actually an anti-pattern (many
people believe this)
Use singletons carefully and only when no other
alternatives, control the number of singleton
classes in your project
Alternative
Dependency injection:
56
Create the object at the beginning and
pass it as a parameter
A story from google
A new developer go to a group and want to try on some methods
testCreditCardCharge() {
CreditCard c = new CreditCard(
"1234 5678 9012 3456", 5, 2008);
c.charge(100);
}
This code:
Only works when you run as part of the suite.
When run in isolation, throws NullPointerException.
When you get your credit card bill, you are out $100 for every time the test runs.
57
A story from google
After a lot of digging, you learn that you need to initialize the
CreditCardProcessor.
testCreditCardCharge() {
CreditCardProcessor.init();
CreditCard c = new CreditCard(
"1234 5678 9012 3456", 5, 2008);
c.charge(100);
}
Still not working
58
A story from google
After a lot of digging, you learn that you need to initialize the
OfflineQueue.
testCreditCardCharge() {
OfflineQueue.init();
CreditCardProcessor.init();
CreditCard c = new CreditCard(
"1234 5678 9012 3456", 5, 2008);
c.charge(100);
}
Still not working
59
A story from google
After a lot of digging, you learn that you need to initialize the
Database.
testCreditCardCharge() {
Database.init();
OfflineQueue.init();
CreditCardProcessor.init();
CreditCard c = new CreditCard(
"1234 5678 9012 3456", 5, 2008);
c.charge(100);
}
But sometimes you have to find out the correct sequence!
60
Solution with dependency injection
testCreditCardCharge() {
Database db = Database();
OfflineQueue q = OfflineQueue(db);
CreditCardProcessor ccp = new CreditCardProcessor(q);
CreditCard c = new CreditCard(
"1234 5678 9012 3456", 5, 2008);
c.charge(ccp, 100);
}
61