Transcript Document

Design
ECE 417/617:
Elements of Software Engineering
Stan Birchfield
Clemson University
From modeling to design
Steps:
1. Analysis and modeling
2. Design
3. Construction
(code generation and testing)
Design involves making the analysis model more
specific, to facilitate construction.
Goal of design is quality.
FURPS
Quality software is
• Functional – capabilities of program
• Usable – human factors, aesthetics
• Reliable – frequency and severity of failure
• Performance – response time, speed
• Supportable – is the code maintainable,
extensible, testable, configurable, easy to
install, etc.
(Developed by Hewlett-Packard in 1980s)
Basic design principles
•
Design is iterative:
–
–
–
•
Architecture is refined over time by successively
filling in details
Refinement is a process of elaboration
Results in hierarchical model
A good design exhibits
–
–
–
abstraction – details are provided in lower levels
modularity – divide-and-conquer via smaller
independent components
refactoring – internal structure of software is
improved without affecting external behavior
Design model
Design model has three aspects:
• Architectural design
• Component-level (data) design
• Interface design
We will consider these in turn,
with UI covered in a separate lecture.
Architectural Design
Architectural design
•
Architecture is a high-level representation of the S/W
with the major components identified
Architectural styles are templates, e.g.,
•
–
–
–
–
–
•
Data-centered
Data-flow
Call and return
Object-oriented
Layered
Architectural patterns define specific approach for
handling some behavioral characteristic of system, e.g.,
–
–
–
concurrency: use O/S features or provide task scheduler
persistence: storage and retrieval of data
distribution: communication of components with one
another. Most common is broker – acts as middle man
between client and server (CORBA).
Style is like “Cape cod, A-frame”. Pattern is like “kitchen”.
Architectural Styles
• Data-centered – subsystems interact
through single repository
• Model / View / Controller
• Call and return (Client / Server)
• Layered (three-tier, four-tier)
• Data-flow (pipe and filter)
Layers and Partitions
• Layer – group of related subsystems
– Layer knows about layers below it, but not
layers above it
– Top layer: no one else knows about it
– Closed architecture – can only access layer
immediately below
– Open architecture – can access any layer
below
• Partition – peer subsystems, each with
different responsibilities
Hierarchical decomposition
Application
Format
Object
Level of abstraction
Presentation
CORBA
Connection
Session
Message
Transport
Socket
Packet
Network
TCP/IP
Frame
DataLink
Physical
Ethernet
Wire
Bit
Example: Open Systems Interconnection (OSI)
Mapping DFD into architecture
•
Transform mapping
–
–
–
–
–
–
–
–
•
transform flow always exists; represents information flow within system; incoming flow
passes through transform center, leads to outgoing flow
To map DFD with transform flow characteristics into specific architectural style,
review model
refine models
determine whether transform or transaction characteristics
isolate transform center
perform first and second level factoring
refine
Transaction mapping
–
–
–
–
–
–
–
–
transaction flow occurs when one input gives rise to several outputs; transaction triggers
data flow along one of many paths
To map DFD with transaction flow characteristics,
review model
refine models
determine whether transform or transaction characteristics
isolate transaction center
map to transform branch
factor and refine
Model / View / Controller (MVC)
• MVC:
– Model subsystems maintain domain
knowledge
– View subsystems display it to the user
– Controller subsystems manage sequence of
interactions with user
• M doesn’t depend upon V or C
• Changes propagated via subscribe/notify
protocol, using Observer design pattern
• Well-suited for interactive systems
MVC Details
Controller
initiator
1
*
repository
Model
1
View
subscriber
*
notifier
MVC Example
MVC Example Details
2:enterNewFileName(file,newName)
3:setName(newName)
:Controller
1:subscribeToFileEvents(file)
5:getName()
:InfoView
:Model
4:notifySubscribedViews(file)
4:notifySubscribedViews(file)
:FolderView
1:subscribeToFileEvents(file)
5:getName()
GUI-Based Programming
Paradigms Compared
Application
output
callbacks
draw
Widgets
Application
input
output
input
The User
Traditional command-line
GUI-based
Event/Message loop
Event loop – pseudocode
int main() {
return WinMain();
}
WinMain() {
while (1) { // loop forever, waiting for an event
if (event_exists) { //there is an event, figure out what to do
if (event == keydown_a) display(‘user pressed the A key’);
else if (event == window_resize) display(‘window
resized’);
else if (event == repaint) display(‘need to repaint
window’);
else if (event == keydown_escape) exit_program();
}
}
}
Event loop – WinMain
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst,
char * cmdParam, int cmdShow)
{
char className [] = "Winnie";
WinClass winClass (WindowProcedure, className, hInst);
winClass.Register ();
WinMaker win ("Hello Windows!", className, hInst);
win.Show (cmdShow);
MSG msg;
int status;
while ((status = ::GetMessage (& msg, 0, 0, 0)) != 0) {
if (status == -1) return -1;
::DispatchMessage (& msg);
}
return msg.wParam;
}
Event loop – WindowProc
LRESULT CALLBACK WindowProcedure (HWND hwnd,
unsigned int message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_DESTROY: ::PostQuitMessage (0); return 0;
}
return ::DefWindowProc (hwnd, message, wParam, lParam );
}
Event loop (cont.)
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow)
{
HWND hwnd;
MSG msg;
//initialization code goes here
while(1) {
// Get message(s) if there is one
if(PeekMessage(&msg,hwnd,0,0,PM_REMOVE)) {
if(msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg); //this calls the CALLBACK function WinProc()
} else {
DrawScene(); //display the OpenGL/DirectX scene
}
}
}
Event loop (cont.)
LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM
lparam)
{
PAINTSTRUCT ps;
// Depending on the message -- we'll do different stuff
switch(message) {
case WM_PAINT:
Draw();
return 0;
// ESC will quit program
case WM_KEYDOWN: //user pressed a key
if(GetAsyncKeyState(VK_ESCAPE)) //it was the escape key
PostQuitMessage(0);
//quit program
return 0;
case WM_DESTROY: //windows wants the program to die
case WM_CLOSE:
//or the user closed the window
PostQuitMessage(0); //quit program
return 0;
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
GUI Concepts
• Widget – graphic object with
functionality; e.g., button, toolbar,
...
• Window – holds widgets
• Child/parent – relationships
between windows
• Event / message – how windows
communicate
Anatomy of a Window
title bar
menu
toolbar
client area
status bar
Microsoft Windows
Programming
• History:
– Win32 API: core library written in C
– MFC: C++ wrappers around most
common Win32 API functions
•
•
•
•
Lots of macros
Lots of legacy code
Not free, not portable
But it works (generally speaking)
Analyzing architectural
designs
Two approaches developed by SEI:
• Architecture trade-off analysis method
(ATAM)
– Collect scenarios and requirements
– Evaluate quality attributes and their sensitivity
– Critique candidate architectures
• Scenario-based architectural analysis
(SAAM)
– Uses scenarios to analyze architectures with
respect to quality attributes
Quality attributes: reliability, performance, security, maintainability, flexibility,
testability, portability, reusability, interoperability
Component-level Design
Component-level design
•
Occurs after the first iteration of architectural
design
Goal: translate the design model into
operational software
Component is set of collaborating classes
Designing components
•
•
•
–
–
–
–
OCL
flow chart
tabular design notation
Decision table has four quadrants specifying
conditions and actions, as well as rules for both
PDL (pseudocode)
Decomposition
System
Subsystem1
Class1a
...
Class1n
...
SubsystemN
ClassNa
...
ClassNn
Coupling and cohesion
• Coupling -- # of dependencies between
subsystems
• Cohesion -- # of dependencies within
subsystem
• Goal: low coupling, high cohesion
• 7 +/- 2 rule – keep number of concepts at
any given layer of abstraction bounded
Additional design principles
•
•
•
•
•
•
•
•
Single responsibility (SRP)
A class should have only one reason to change
Open-closed (OCP)
Software entities should be open for extension but closed for modification
(achieved via inheritance)
Liskov substitution (LSP)
Subclasses should be substitutable for their base classes
Dependency inversion (DIP)
Abstractions should not depend upon details
Interface segregation (ISP)
Many client-specific interfaces are better than one general purpose
interface
Release reuse equivalency (REP)
Granule of reuse is granule of release
Common closure (CCP)
Classes that change together belong together
Common reuse (CRP)
Classes in a package are reused together
Data structures and flow
•
Software system is composed of
– data structures, and
– data flow
•
Which is more important?
“Show me your code and conceal your data structures,
and I shall continue to by mystified. Show me your
data structures and I won’t usually need your code.
It will be obvious.” – Fred Brooks
What is a Design Pattern?
• A design pattern
– abstracts a recurring design structure
– comprises class and/or object
•
•
•
•
dependencies,
structures,
interactions, or
conventions
– distills design experience
Re-use
• Code re-use
– Don’t reinvent the wheel
– Requires clean, elegant, understandable,
general, stable code
– leverage previous work
• Design re-use
– Don’t reinvent the wheel
– Requires a precise understanding of common,
recurring designs
– leverage previous work
Some design patterns
•
•
•
•
•
•
•
•
•
Abstract factory
Adapter
Bridge
Command
Composite
Façade
Subject / Observer
Proxy
Strategy
Subject-observer
[from Vlissides]
Subject-observer (cont.)
Subject
Register(Observer)
Unregister(Observer)
NotifyAll()
1
* Observer
OnUpdate()
for all o in observers {
o.OnUpdate()
}
Subject-observer (cont.)
Subject
Register(Observer)
Unregister(Observer)
NotifyAll()
ConcreteSubject
1
*
Observer
virtual OnUpdate()
for all o in observers {
o.OnUpdate()
}
ConcreteObserver
virtual OnUpdate()
Model / view / controller (MVC)
Model
}
OnUpdate()
calls Register()
Set()
Controller
(holds data)
Set()
View
Create()
Main
Model m;
Controller c(&m);
View v(&c);
Register()
Model
{
(mediates)
Create()
Controller
(displays data)
Create()
View
MVC (cont.)
Subject
Register(Observer)
Unregister(Observer)
NotifyAll()
Controller
1
*
Observer
virtual OnUpdate()
for all o in observers {
o.OnUpdate()
}
View
virtual OnUpdate()
MVC (cont.)
class Observer
{
protected:
virtual void OnUpdate(MsgId message_id) = 0;
};
class Subject
{
public:
enum MsgId {};
void RegisterObserver(Observer* obs);
virtual void NotifyAllObservers(MsgId message_id) {
for (int i=0 ; i<m_observers.size() ; i++) {
m_observers[i]->OnUpdate(message_id);
}
}
private:
std::vector<Observer*> m_observers;
};
MVC (cont.)
class Controller : public Subject
{
Controller(Data* d) : m_data(d) {}
const Data* GetData() const;
void AddSphere(const Sphere& s) {
m_data->AddSphere(s);
NotifyAllObservers(ADD_SPHERE);
}
private:
Data* m_data;
};
MVC (cont.)
class MainWnd : public Observer, CWnd
{
public:
MainWnd(Controller* c) : m_controller(c) {
c.Register(this);
}
virtual void OnUpdate(int message_id) {
switch (message_id) {
case Subject::ADD_SPHERE:
...
}
}
private:
Controller* m_controller;
};
Adapter
• You have
– legacy code
– current client
• Adapter changes interface of legacy code
so client can use it
• Adapter fills the gap b/w two interfaces
• No changes needed for either
– legacy code, or
– client
Adapter (cont.)
class NewTime
{
public:
int GetTime() {
return m_oldtime.get_time() * 1000 + 8;
}
private:
OldTime m_oldtime;
};
Command
• You have commands that need to be
– executed,
– undone, or
– queued
• Command design pattern separates
– Receiver from Invoker from Commands
• All commands derive from Command
and implement do(), undo(), and
redo()
Implementing ‘Undo/Redo’
• Multi-level undo/redo requires two
classes:
– Command
– CommandManager
class Command
{
public:
virtual bool Execute() = 0;
virtual bool Unexecute() = 0;
virtual ~Command() { }
};
class CommandManager
{
private:
typedef list<Command*> CommandList;
CommandList m_undoList;
CommandList m_redoList;
public:
void DoCommand(Command* com);
void Undo();
void Redo();
};
http://www.codeproject.com/KB/cpp/undoredo_cpp.aspx
Facade
• You
– have a set of related classes
– want to shield the rest of the system
from these details
• Facade provides a simplified
interface
• Encapsulates a subsystem
Composite
• You want uniformly to treat
– items (atomic elements), and
– groups (containing items or other
groups)
• Composite interface specifies
operations that are shared between
items and groups
• Examples: hierarchy of files and
directories, groups of drawable
elements
Composite (cont.)
Composite
Item
Group
Proxy
• You want to
– delay expensive computations,
– use memory only when needed, or
– check access before loading an object into
memory
• Proxy
– has same interface as Real object
– stores subset of attributes
– does lazy evaluation
Strategy
• You want to
– use different algorithms depending upon the
context
– avoid having to change the context or client
• Strategy
– decouples interface from implementation
– shields client from implementations
– Context is not aware which strategy is being
used; Client configures the Context
– strategies can be substituted at runtime
– example: interface to wired and wireless
networks
Strategy (cont.)
Client
Policy
Context
Strategy
Concrete
StrategyA
Concrete
StrategyB
Strategy (cont.)
Lots of switch statements is evidence of “code smell”:
Polymorphism, using strategy pattern, cleans this up:
http://codebetter.com/blogs/jeremy.miller/archive/2006/04/11/142665.aspx
Bridge
• You
– have several different implementations
– need to choose one, possibly at run time
• Bridge
– decouples interface from implementation
– shields client from implementations
– Abstraction creates and initializes the
ConcreteImplementations
– Example: stub code, slow code, optimized
code
Bridge (cont.)
Client
Abstraction
Implementor
Concrete
ImplementorA
Refined
Abstraction
Concrete
ImplementorB
Design pattern space
[from Vlissides]