CS5103 Software Engineering Lecture 09 Software Design and Design Patterns
CS5103 Software
EngineeringLecture 09
Software Design and Design Patterns
2
Last class
Sequence diagrams Software architecture
Why? Higher level design of larger software projects
Software architectural styles Pipe and Filter Layered Repository
3
Today’s class
Software Design Process
Factors
Measures
Design Patterns Composite pattern
Factory pattern
Visitor pattern
4
Software Design Process
Software design is usually created in two stages
Architecture design
Detail design (component-level design)
Design patterns
Design classes Design review
Other design issues Refactoring
UI Design
5
Software Design Factors
Fundamental software design factors Modularity
Abstraction
Information hiding
Component independence
Fault prevention and fault tolerance
6
Modularity and Abstraction
When we consider modular solutions to any problems, many levels of abstraction can be posed
At the highest level of abstraction, a solution is stated in broad terms of problem domain: architecture
At the lower levels of abstraction, a more detailed description of the solution is provided: class diagrams
Modularity hides details and facilitates evolvement
Each component hides a design decision from the others
7
Component Independent
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
8
Coupling and Cohesion
Coupling Two components are highly coupled when there is a
great deal of dependence between them
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 A component is cohesive if the internal parts of the
component are related to each other and to its overall purpose
9
Decoupling
Most difficult part in design: Need tradeoff
Consider the following case: Online and offline bookstore components
Both need shopping cart checkout
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
10
Fault defense & tolerance
Defensive design anticipates situations the might lead to problems
Network Failure
Data corruption
Invalid user inputs
Tolerate runtime errors Exception handling
Redundant components (distributed system or critical software)
Timely error reporting
11
Criteria for Good Software Design
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
12
Criteria for Good Software Design
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
13
Software Design Evaluation and Validation
We check a design in two different ways 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
14
Measuring Software Design Quality
We check a design using a set of measures Coupling Cohesion Complexity
Basic metrics: size Depths of relations Cyclomatic complexity
15
Design reviews
We check a design Designers
Customers
Analysts
prospective users
Developers
Moderator leading the discussions
Secretary recording the issues
16
Design Patterns
Become popular due to a book Design Patterns: Elements of Reusable Object-O
riented Software Gang of Four: Gamma, Erich; Richard Helm, Ralp
h Johnson, and John Vlissides Provide solutions for common problems
in micro-design
17
Design Patterns Structure
Name Important to know for easier communication between
designers
Problem solved When to apply the pattern
Solution Usually a class diagram segment (sometimes
attributes and operations)
18
Design Patterns
Structure Patterns Composite
Creation Patterns Factory
Behavioral Patterns Visitor
19
Running Example
A Document Editor
Text and graphics can be freely mixed
Graphical user interface
Support different look-and-feel GUI styles
Traversal operations: spell checking
20
Composite Pattern: Example
A document is represented by structure Primitive glyphs
Characters, circles, pictures
Lines: A sequence of glyphs
Columns: A sequence of Lines
Pages: A sequence of Columns
Documents: A sequence of Pages
21
Example of Hierarchical Document
22
Possible Designs?
Classes of Character, Circle, Pictures, lines, Columns, pages, document Composition relationship between classes Not so good, why? A lot of duplication:
all classes has onClick, draw behavior Difficult to add or remove levels in hierarchy Traverse/display operations need to change for a
ny change of the hierarchy
Document
Page
Column
Line
Glyph
CharacterPicture
1
*
1*
1*
1
*
23
Alternate Designs
One class of Glyph 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
24
Logic Object Structure
25
Logic Object Structure
26
Composite Pattern
Applies to any hierarchy structure Leaves and internal nodes have similar
functionality Pros:
Easy to add, remove new types
Clean interface Cons:
Add corner cases
Enforce certain type of elements only have certain types of children
27
Problem: Supporting look-and-feel settings
Different look-and-feel standards Appearance of scrollbars, menus, windows, et
c., set by the user We want to support them all
For example: having classes MotifScrollBar and WindowsScrollBar
Both are subclasses of ScrollBars How should we create a new scrollbar in a wind
ow?
28
Possible designs?
TerribleScrollBar sc = new WindowScrollBar();
Better, problems?If (style==MOTIF){
sc = new MotifScrollBar();}else{ sc = new WindowScrollBar();} Conditions for other UI elements: menus, etc. Hard to add new styles
29
Factory Pattern
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
30
Factory Pattern
31
Factory Pattern: factory design
abstract class GUIFactory{ abstract ScrollBar CreateScrollBar(); abstract Menu CreateMenu(); ...}
class MotifFactory extends GuiFactory{ ScrollBar CreateScrollBar(){ return new MotifScrollBar() } Menu createMenu(){ return new MotifMenu(); } ...}
32
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();
33
Factory Pattern
Applies to the object creation of a family of classes
The factory can be changed at runtime
Pros & Cons 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
34
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 words, Grammar checking
35
Possible designclass 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);
…}
36
Other Actions
Document Stats counting words, counting pictures, counting lines, columns, pages)
Find a word
Change line-break rules
…
37
Now we have
A large number of similar methods All need to traverse the document
Code duplication always causes problems 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
38
Solution
Visitor pattern Decouple traverse process and action
Write traverse code only once
Each element in the hierarchy under traverse has an “action” code
39
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.
40
Solution
41
Code of SpellCheckVisitor
class SpellCheckVisitor extends Visitor{ char[] curWord = {}; void visitChar(Character c){ if(c==SPACE): spellCheck(curWord); curWord.clear(); else: curWord.add(c); } }
42
Still have problems
How about counting all glyphs (including picture, character, circle)?
Need to change visitPicture, visitCharacter, and visitCircle?
Add visitGlyph
43
Add VisitGlyph
class Glyph{
…
scan(Visitor){
for each c in children:
v.visitGlyph(c)
c.Scan(v)
}
…
}
44
Code of CountGlyphVisitor
class CountGlyphVisitor extends Visitor{
int count = 0;
void visitGlyph(Glyph g){
if(g.children.length==0):
count++;
}
}
}
45
Summary of design patterns
Major aim: decoupling
pros: more flexibility less changes when modification is required
Cons: 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!
46
Other useful design patterns
Observer Facade Factory method Decorator Bridge See them in wiki pages or read the book
Design Patterns: Elements of Reusable Object-Oriented Software
47
Today’s class
Software Design Design process
Design factors
Design evaluation
Design Patterns Composite pattern
Factory pattern
Visitor pattern
48
Next Class
Software Implementation: Versioning Why versioning?
Versioning tools CVS SVN GIT
49
Thanks!
50
A controversial pattern: singleton pattern
Problem 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 Instance()
SingletonOp()
GetSingletonData()
static uniqueInstance
singletonDatareturn uniqueinstance
Singleton Pattern: code
class Singleton {
public:
static Singleton Instance();
}
protected:
Singleton();
private:
Static Singleton _instance
// Only one instance can ever be created.
// Creation hidden inside 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.
54
Singleton Pattern
Pros 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
55
View points
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
56
Alternative
Dependency injection: Create the object at the beginning and
pass it as a parameter
57
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.
58
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
59
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
60
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!
61
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);}