Basic Class Design Example: Payroll Purpose: Picture the object-creation, message-passing interplay...
Transcript of Basic Class Design Example: Payroll Purpose: Picture the object-creation, message-passing interplay...
Basic Class Design
Example: Payroll
Purpose:
Picture the object-creation, message-passing interplay of objects in an executing program.
Statement of The Problem:
Given a source of time card information and a personnel file, print payroll checks
What Objects Would You Expect?
Statement of The Problem (again):
Given a source of time card information
and a personnel file, print payroll checks
Common heuristic: look for the nouns.
Payroll Classes
• PayrollMaster• Employee• PersonnelFile• TimeCard
• TimeCardFile• Check• SS#• Hours
Payroll Objects
TimeCard
getSSgetTim
e
TimeCard File
getCard
Payroll MasterDoPayroll
PersonnelFile
lookup
SSmatch
TimegetHours
Employee
PayYourself
Checkprin
t
Programmain
TimeCard File
getCard
Payroll MasterDoPayroll
Payroll MasterDoPayroll
PersonnelFile
lookup
TimeCard File
getCard
Payroll Program (1)
Programmain
Payroll MasterDoPayroll
PersonnelFile
lookup
PersonnelFile
lookup
TimeCard File
getCard
TimeCard File
getCard
Payroll MasterDoPayroll
PersonnelFile
lookup
TimeCard
getSSgetTim
e
TimeCard
getSSgetTim
e
TimeCard
getSSgetTim
e
PayrollMaster: DoPayroll (1)
TimeCard
getSSgetTim
e
TimeCard File
getCard
Payroll MasterDoPayroll
PersonnelFile
lookupget SS
SSmatchSSmatch
get SS
SSmatch
get SS
PayrollMaster: DoPayroll (2)
get SS
SSmatch
get Time
TimegetHours
get Timeget Time
TimegetHours
PayrollMaster: DoPayroll (3)
TimeCard
getSSgetTim
e
TimeCard File
getCard
Payroll MasterDoPayroll
PersonnelFile
lookup
SSmatch
get Time
TimegetHoursTimegetHoursTimegetHours
Personnel: Lookup
TimeCard
getSSgetTim
e
TimeCard File
getCard
Payroll MasterDoPayroll
PersonnelFile
lookup
SSmatch
TimegetHours
Employee
PayYourselfEmployee
PayYourselfEmployee
PayYourself
PayrollMaster: DoPayroll (4)
TimeCard
getSSgetTim
e
TimeCard File
getCard
Payroll MasterDoPayroll Personn
elFilelookup
SSmatch
TimegetHours
Employee
PayYourself
Checkprin
t
Checkprin
t
Checkprin
t
Checkprin
t
Checkprin
t
Checkprin
t
Payroll Program (2)
TimeCard
getSSgetTim
e
TimeCard File
getCard
Payroll MasterDoPayroll
PersonnelFile
lookup
SSmatch
TimegetHours
Employee
PayYourself
Checkprin
t
Programmain
A Peculiar Employee Design?
• Since when do employees create their own
checks?
• Since when are employees trusted to determine
their own pay?
(not in OUR contract!)
SMART and HELPFUL Objects
OOP and O-O Design
• Can't rush in and “program”
• Design phase needed even in simple problems– desirable in procedural programming– sine qua non in O-O world
• O-O design methodologies:– numerous– we'll consider just one simple one
Kindergarten OODStatement of
Problem
Possible Objects
Primary Object
Behavior
Interface
Sample Use
Implement
Kindergarten OOD
• Not appropriate for all problems
• Works surprisingly well on many– great for CS1
• Illustrate with an example:
Find the value of a portfolio of stocks based on “ticker-tape” information
Statement of Problem:
Find the value of a portfolio of stocksbased on "ticker-tape" information.
Possible Objects:
• Portfolio
• Holding (a portfolio item)
• Value
• TickerTape
Primary Object?
• not Holding
• not Value
• Portfolio vs. TickerTape?
Portfolio vs. TickerTape?
• Both primary in the sense of independence
• But to which object should we send a messageto solve our problem?
Is Portfolio the Primary Object?
• If so, Portfolio has this behavior:
get Value of Portfolio, given TickerTape
Is TickerTape the Primary Object?
• If so, TickerTape has this behavior:– get Value of Portfolio, given Portfolio
• Should TickerTape be responsible for computing the Value of a Portfolio?
Responsibility-Driven Design:
• objects should be responsible for themselves
• example:– objects should be responsible for their own
initialization (constructors)
• TickerTape should not be responsible for Value of a Portfolio, Portfolio should
• Primary Object:Portfolio
Behavior of Portfolio:
• get Value, given TickerTape
• constructor, given a file listing of a portfolio
Interface of Portfolio:
class Portfolio {Portfolio create()Value getValue(TickerTape t)
}
Sample Use:
create TickerTape tcreate Portfolio pto p: get Value v, given tto v: print
Implementing Portfolio:class Portfolio {
constructor() {}
Value getValue(TickerTape t) {}
}
Implementing Portfolio: getValue (1):class Portfolio {
Value getValue(TickerTape t) {for each Holding h in Collection c of Holdings {
get the Value of hincrease the total by v
}return total
}
}•Needed:
•STATE: Collection object, c
A Portfolio HAS-A collection of holdings•Local Value object, total
Implementing Portfolio: getValue (2):class Portfolio {
Value getValue(TickerTape t) {Value total initialized to 0
for each Holding h in Collection c of Holdings {get the Value of hincrease the total by v
}return total
}
STATE: Collection c}
Getting The Value of a Holding (1)
• This is OOP
• Ya want something done, send an object a
message
to h: getValue
Getting The Value of a Holding (2)to h: getValue
• Problem: a Holding is responsible for • name of stock
• number of shares
• NOT current market value
• Solution: send h an object that has the necessary behavior
to h: getValue given TickerTape t
Increasing a Value
• This is OOP
• Ya want something done, send an object a
message
to total: increase by ...
Implementing Portfolio: getValue (3):class Portfolio {
Value getValue(TickerTape t) {Value total initialized to 0for each Holding h in Collection c of Holdings {
to h: get the Value v of your stock, given tto total: increase by v
}return total
}
STATE: Collection c}
• Remark: Who initializes the Collection?
The Portfolio Constructor (1)class Portfolio {
constructor() {create Collection c... ???
}
...
STATE: Collection c
}
Constructor Questions and Answers• Questions:
– where will the portfolio data come from?– in what form will it be?
• Answers (let's say):– from a TokenSource– a sequence of (stock name and number) pairs
• Question:– Where should the responbility for creating TokenSource
lie?
The Portfolio Constructor (2)class Portfolio {
constructor(TokenSource src) {create Collection ccreate Holding h, given srcwhile h was created successfully {
to c: add hcreate Holding h, given src
}}…
STATE: Collection c}
Portfolio Class:class Portfolio {
constructor(TokenSource src) {create Collection ccreate Holding h, given srcwhile h was created successfully {
to c: add hcreate Holding h, given src
}}Value getValue(TickerTape t) {
Value total initialized to 0for each Holding h in Collection c of Holdings { to h: get the Value v of your stock, given t to total: increase by v}return total
}
STATE: Collection c}
Class Summary
Completed:– Portfolio
Yet To Complete:– TickerTape
– TokenSource
– Collection
– Holding
– Value
Details of Remaining Classes:• TickerTape— constructor• TokenSource — constructor
get String• Collection— constructor
add... some way of iterating …
• Holding— constructor, given TokenSourceget Value given TickerTape
• Value— constructor, given an integer valueincrease, given a Valueprint
NEXT STEP: Pick a class and follow same procedure…
• TickerTape
• TokenSource
• Collection
• Holding
• Value
Statement of SubProblem…
… skip steps because
behavior
interface
have been determined
Behavior of Holding:
• create, given TokenSource
• get Value given TickerTape
Interface of Holding:
class Holding {
constructor(TokenSource src)
Value getValue(TickerTape t)
}
Sample Use:
... from implementation of Portfolio
Implementing Holding:
class Holding {
constructor(TokenSource src) {}
Value getValue(TickerTape t) }}
}
Implementing Holding: getValueclass Holding {
Value getValue(TickerTape t) {to t: get Value v of stock named by my StockNameto v: multiply by my Numberreturn v
}}
• Remarks:– the object must maintain a StockName and a Number,
call them sn and n
Implementing Holding: STATE
class Holding {
Value getValue(TickerTape t) {to t: get Value v given snto v: multiply by nreturn v
}
STATE:StockName snNumber n
}
Implementing Holding: constructorclass Holding {
constructor(TokenSource src) {create StockName sn, given srccreate Number n, given src
}
...
STATE:StockName snNumber n
}
• Remark:Each class bears the responsibility for doingmost of the work to create its own instances
The Holding Classclass Holding {
constructor(TokenSource src) {create StockName sn, given srccreate Number n, given src
}
Value getValue(TickerTape t) {to t: get Value v given snto v: multiply by nreturn v
}
STATE:StockName snNumber n
}
Class Summary
Completed:– Portfolio
– Holding
Yet To Complete:– TickerTape
– TokenSource
– Collection
– Value
– Number
– StockName
Details of Remaining Classes (I):• TickerTape— constructor
– get Value given a StockName
• TokenSource — constructor– get String
• Collection— constructor– add– ... some way of iterating …
NEW!
Details of Remaining Classes (II):
• Value— constructor, given an integer value– increase, given a Value– multiply, given a Number– print
• Number— constructor
• StockName— constructor
NEW!
NEW!
NEXT STEP: Pick a class and follow procedure....
• TickerTape
• TokenSource
• Collection
• Value
• Number
• StockName
Statement of SubProblem:
• ... skip steps because behavior, interface has been determined
Behavior of TickerTape:
• Create
• get Value given StockName
Interface of TickerTape:
class TickerTape {
constructor()
TickerTape getValue(StockName sn)
}
Sample Use:
... from implementation of Holding
Implementing TickerTapeclass TickerTape {
constructor() {}
Value getValue(StockName sn) {}
}
Implementing TickerTape: getValue
Remark: need a Collection in my state
class TickerTape {
Value getValue(StockName sn) {for each StockQuote s
in my Collection c of StockQuotes {to s: does sn match?if yes {
to s: getValue vreturn v
}}error
}}
Implementing TickerTape: Stateclass TickerTape {
Value getValue(StockName sn) {for each StockQuote s
in my Collection c of StockQuotes {to s: does sn match?if yes {
to s: getValue vreturn v
}}error
}
STATE:Collection c}
Implementing TickerTape: constructorclass TickerTape {
constructor(TokenSource src) {create Collection ccreate StockQuote s given srcwhile not failure {
to c: add screate StockQuote s given src
}}
...
STATE:Collection c}
The TickerTape Classclass TickerTape {
constructor(TokenSource src) {create Collection ccreate StockQuote s given srcwhile not failure {
to c: add screate StockQuote s given src
}}
The TickerTape Class (continued)
Value getValue(StockName sn) {for each StockQuote s
in my Collection c of StockQuotes {to s: does sn match?if yes {
to s: getValue vreturn v
}}error}STATE:Collection c
}
Class Summary
Completed:– Portfolio
– Holding
– TickerTape
Yet To Complete:– TokenSource
– Collection
– Value
– Number
– StockName
– StockQuote
Details of Remaining Classes (I):• TokenSource — constructor
– get String• Collection— constructor
– add– ... some way of iterating …
• Value— constructor, given an integer value– increase, given a Value– multiply, given a Number– print
Details of Remaining Classes (II):
• Number— constructor
• StockName— constructor
• StockQuote— constructor, given a TokenSource– match a StockName– return the Value of a stock
NEW!
NEXT STEP: Pick a class and follow procedure....
• TickerTape
• TokenSource
• Collection
• Value
• Number
• StockName
• StockQuote
Statement of SubProblem:
... skip steps because behavior, interface has been determined
Behavior of StockQuote:
• create, given a TokenSource
• get Value
• is match? given a StockName
Interface of StockQuote:
class StockQuote {
constructor(TokenSource src)
Value getValue()
boolean isMatch(StockName sn)
}
Sample Use:
• ... from implementation of TickerTape
Implementing StockQuote
class StockQuote {constructor(TokenSource src) {
}
StockQuote getValue() {
}
boolean isMatch(StockName sn) {
}
}
Implementing StockQuote (I)class StockQuote {
constructor(TokenSource src) {}
StockQuote getValue() {return v;
}
boolean isMatch(StockName sn) {to sn: does my StockName sn match?if yes return true else return false
}
STATE:Value vStockName sn
}
Implementing StockQuote (II)class StockQuote {
constructor(TokenSource src) {create StockName sn, given srccreate Value v, given src
}
...
STATE:Value vStockName sn
}
The StockQuote Classclass StockQuote {
constructor(TokenSource src) {create StockName sn, given srccreate Value v, given src
}
StockQuote getValue() {return v;
}
boolean isMatch(StockName sn) {to sn: does my StockName sn match?if yes return true else return false
}
STATE:Value vStockName sn
}
Class Summary
Completed:– Portfolio
– Holding
– TickerTape
– StockQuote
Yet To Complete:– TokenSource
– Collection
– Value
– Number
– StockName
Details of Remaining Classes (I):• TokenSource — constructor
– get String• Collection— constructor
– add– ... some way of iterating …
• Value— constructor, given an integer value– increase, given a Value– multiply, given a Number– print
Details of Remaining Classes (II):
• Number— constructor
• StockName— constructor– is Match? given another StockName
NEW!
NEXT STEP: Pick a class and follow procedure....
• TickerTape
• TokenSource
• Collection
• Value
• Number
• StockName
Statement of SubProblem:
• ... skip steps because behavior, interface has been determined
Behavior of Value:
• create, given a TokenSource
• increase, given a Value
• multiply, given a Number
Interface of Value:
class Value {
Value create(TokenSource src)
void increase(Value v)
void multiply(Number n)
void print()
}
Sample Use:
... from implementation of TickerTape
Implementing Value
class Value {
Value create(TokenSource src) {
}
void increase(Value v) {
}
void multiply(Number n) {
}
void print() {
}
}
Implementing Value: constructor
class Value {constructor(TokenSource src) {
to src: get String integerPartto src: get String fractionto fraction: contains / ?if no
to src: put back String fraction// just use integerPart
else// use integerPart and fraction
}...
}
Implementing Value: other methodsclass Value {
Value create(TokenSource src) {...
}
void increase(Value v) {// defer
}
void multiply(Number n) {// defer
}
void print() {// defer
}
STATE: ???}
Class Summary
Completed:– Portfolio
– Holding
– TickerTape
– StockQuote
– Value (partially)
Yet To Complete:– TokenSource
– Collection
– Number
– StockName
Details of Remaining Classes:• TokenSource — constructor
– get String– put back String, given String
• Collection— constructor– add– ... some way of iterating …
• Number— constructor
• StockName— constructor– is Match? given another StockName
NEW!
NEXT STEP:
And so on …
(I'm tired now— aren't you?)