Basic Class Design Example Payroll Purpose Picture the
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 • • Payroll. Master Employee Personnel. File Time. Card • • Time. Card. File Check SS# Hours
Payroll Objects Program main Personnel File lookup Payroll Master Do. Payroll Time. Card File Time get. Card get. Hours Pay. Yourself Time. Card Employee get. Time get. SS Check print SS match
Payroll Program (1) Program main Personnel File lookup Time. Card File get. Card Payroll Master Do. Payroll
Payroll. Master: Do. Payroll (1) Payroll Master Do. Payroll Personnel File Time. Card File lookup get. Card Time. Card get. Time get. SS
Payroll. Master: Do. Payroll (2) Payroll Master Do. Payroll Personnel File Time. Card File get SS lookup get. Card SS SS Time. Card get. Time get. SS match
Payroll. Master: Do. Payroll (3) Payroll Master Do. Payroll Personnel File Time. Card File lookup get Time get. Card Time get. Hours Time. Card get. Time get. SS SS match
Personnel: Lookup Payroll Master Do. Payroll Personnel File Time. Card File lookup get. Card Pay. Yourself Employee Time get. Hours Time. Card get. Time get. SS SS match
Payroll. Master: Do. Payroll (4) Payroll Master Do. Payroll Personnel File lookup Time. Card File get. Card Time get. Hours Pay. Yourself Employee Time. Card get. Time get. SS Check print SS match
Payroll Program (2) Program main Personnel File lookup Payroll Master Do. Payroll Time. Card File Time get. Card get. Hours Pay. Yourself Time. Card Employee get. Time get. SS Check print SS match
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 OOD Statement 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 CS 1 • 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 stocks based on "ticker-tape" information.
Possible Objects: • • Portfolio Holding (a portfolio item) Value Ticker. Tape
Primary Object? • not Holding • not Value • Portfolio vs. Ticker. Tape?
Portfolio vs. Ticker. Tape? • Both primary in the sense of independence • But to which object should we send a message to solve our problem?
Is Portfolio the Primary Object? • If so, Portfolio has this behavior: get Value of Portfolio, given Ticker. Tape
Is Ticker. Tape the Primary Object? • If so, Ticker. Tape has this behavior: – get Value of Portfolio, given Portfolio • Should Ticker. Tape 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) • Ticker. Tape should not be responsible for Value of a Portfolio, Portfolio should • Primary Object: Portfolio
Behavior of Portfolio: • get Value, given Ticker. Tape • constructor, given a file listing of a portfolio
Interface of Portfolio: class Portfolio { Portfolio create() Value get. Value(Ticker. Tape t) }
Sample Use: create Ticker. Tape t create Portfolio p to p: get Value v, given t to v: print
Implementing Portfolio: class Portfolio { constructor() { } Value get. Value(Ticker. Tape t) { } }
Implementing Portfolio: get. Value (1): class Portfolio { Value get. Value(Ticker. Tape t) { for each Holding h in Collection c of Holdings { get the Value of h increase the total by v } return total } } • Needed: • STATE: Collection object, c A Portfolio HAS-A collection of holdings • Local Value object, total
Implementing Portfolio: get. Value (2): class Portfolio { Value get. Value(Ticker. Tape t) { Value total initialized to 0 for each Holding h in Collection c of Holdings { get the Value of h increase 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: get. Value
Getting The Value of a Holding (2) to h: get. Value • 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: get. Value given Ticker. Tape t
Increasing a Value • This is OOP • Ya want something done, send an object a message to total: increase by. . .
Implementing Portfolio: get. Value (3): class Portfolio { Value get. Value(Ticker. Tape t) { Value total initialized to 0 for 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 } • 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 Token. Source – a sequence of (stock name and number) pairs • Question: – Where should the responbility for creating Token. Source lie?
The Portfolio Constructor (2) class Portfolio { constructor(Token. Source src) { create Collection c create Holding h, given src while h was created successfully { to c: add h create Holding h, given src } } … STATE: Collection c }
Portfolio Class: class Portfolio { constructor(Token. Source src) { create Collection c create Holding h, given src while h was created successfully { to c: add h create Holding h, given src } } Value get. Value(Ticker. Tape t) { Value total initialized to 0 for 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: – – – Ticker. Tape Token. Source Collection Holding Value
Details of Remaining Classes: • Ticker. Tape— constructor • Token. Source — constructor get String • Collection— constructor add. . . some way of iterating … • Holding— constructor, given Token. Source get Value given Ticker. Tape • Value— constructor, given an integer value increase, given a Value print
NEXT STEP: Pick a class and follow same procedure… • • • Ticker. Tape Token. Source Collection Holding Value
Statement of Sub. Problem… … skip steps because behavior interface have been determined
Behavior of Holding: • create, given Token. Source • get Value given Ticker. Tape
Interface of Holding: class Holding { constructor(Token. Source src) Value get. Value(Ticker. Tape t) }
Sample Use: . . . from implementation of Portfolio
Implementing Holding: class Holding { constructor(Token. Source src) { } Value get. Value(Ticker. Tape t) } } }
Implementing Holding: get. Value class Holding { Value get. Value(Ticker. Tape t) { to t: get Value v of stock named by my Stock. Name to v: multiply by my Number return v } } • Remarks: – the object must maintain a Stock. Name and a Number, call them sn and n
Implementing Holding: STATE class Holding { Value get. Value(Ticker. Tape t) { to t: get Value v given sn to v: multiply by n return v } STATE: } Stock. Name sn Number n
Implementing Holding: constructor class Holding { constructor(Token. Source src) { create Stock. Name sn, given src create Number n, given src }. . . STATE: Stock. Name sn Number n } • Remark: Each class bears the responsibility for doing most of the work to create its own instances
The Holding Class class Holding { constructor(Token. Source src) { create Stock. Name sn, given src create Number n, given src } Value get. Value(Ticker. Tape t) { to t: get Value v given sn to v: multiply by n return v } STATE: } Stock. Name sn Number n
Class Summary Completed: – Portfolio – Holding Yet To Complete: – – – Ticker. Tape Token. Source Collection Value Number Stock. Name
Details of Remaining Classes (I): • Ticker. Tape— constructor – get Value given a Stock. Name • Token. Source — 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 • Stock. Name— constructor NEW !
NEXT STEP: Pick a class and follow procedure. . • • • Ticker. Tape Token. Source Collection Value Number Stock. Name
Statement of Sub. Problem: • . . . skip steps because behavior, interface has been determined
Behavior of Ticker. Tape: • Create • get Value given Stock. Name
Interface of Ticker. Tape: class Ticker. Tape { constructor() Ticker. Tape get. Value(Stock. Name sn) }
Sample Use: . . . from implementation of Holding
Implementing Ticker. Tape class Ticker. Tape { constructor() { } Value get. Value(Stock. Name sn) { } }
Implementing Ticker. Tape: get. Value class Ticker. Tape { Value get. Value(Stock. Name sn) { for each Stock. Quote s in my Collection c of Stock. Quotes { to s: does sn match? if yes { to s: get. Value v return v } } error } } Remark: need a Collection in my state
Implementing Ticker. Tape: State class Ticker. Tape { Value get. Value(Stock. Name sn) { for each Stock. Quote s in my Collection c of Stock. Quotes { to s: does sn match? if yes { to s: get. Value v return v } } error } STATE: } Collection c
Implementing Ticker. Tape: constructor class Ticker. Tape { constructor(Token. Source src) { create Collection c create Stock. Quote s given src while not failure { to c: add s create Stock. Quote s given src } }. . . STATE: } Collection c
The Ticker. Tape Class class Ticker. Tape { constructor(Token. Source src) { create Collection c create Stock. Quote s given src while not failure { to c: add s create Stock. Quote s given src } }
The Ticker. Tape Class (continued) Value get. Value(Stock. Name sn) { for each Stock. Quote s in my Collection c of Stock. Quotes { to s: does sn match? if yes { to s: get. Value v return v } } error } STATE: Collection c }
Class Summary Completed: – Portfolio – Holding – Ticker. Tape Yet To Complete: – – – Token. Source Collection Value Number Stock. Name Stock. Quote
Details of Remaining Classes (I): • Token. Source — 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 NEW • Stock. Name— constructor ! • Stock. Quote— constructor, given a Token. Source – match a Stock. Name – return the Value of a stock
NEXT STEP: Pick a class and follow procedure. . • • Ticker. Tape Token. Source Collection Value Number Stock. Name Stock. Quote
Statement of Sub. Problem: . . . skip steps because behavior, interface has been determined
Behavior of Stock. Quote: • create, given a Token. Source • get Value • is match? given a Stock. Name
Interface of Stock. Quote: class Stock. Quote { constructor(Token. Source src) Value get. Value() boolean is. Match(Stock. Name sn) }
Sample Use: • . . . from implementation of Ticker. Tape
Implementing Stock. Quote class Stock. Quote { constructor(Token. Source src) { } Stock. Quote get. Value() { } boolean is. Match(Stock. Name sn) { } }
Implementing Stock. Quote (I) class Stock. Quote { constructor(Token. Source src) { } Stock. Quote get. Value() { return v; } boolean is. Match(Stock. Name sn) { to sn: does my Stock. Name sn match? if yes return true else return false } STATE: } Value v Stock. Name sn
Implementing Stock. Quote (II) class Stock. Quote { constructor(Token. Source src) { create Stock. Name sn, given src create Value v, given src }. . . STATE: } Value v Stock. Name sn
The Stock. Quote Class class Stock. Quote { constructor(Token. Source src) { create Stock. Name sn, given src create Value v, given src } Stock. Quote get. Value() { return v; } boolean is. Match(Stock. Name sn) { to sn: does my Stock. Name sn match? if yes return true else return false } STATE: } Value v Stock. Name sn
Class Summary Completed: – – Portfolio Holding Ticker. Tape Stock. Quote Yet To Complete: – – – Token. Source Collection Value Number Stock. Name
Details of Remaining Classes (I): • Token. Source — 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 • Stock. Name— constructor NEW – is Match? given another Stock. Name !
NEXT STEP: Pick a class and follow procedure. . • • • Ticker. Tape Token. Source Collection Value Number Stock. Name
Statement of Sub. Problem: • . . . skip steps because behavior, interface has been determined
Behavior of Value: • • create, given a Token. Source increase, given a Value multiply, given a Number print
Interface of Value: class Value { Value create(Token. Source src) void increase(Value v) void multiply(Number n) void print() }
Sample Use: . . . from implementation of Ticker. Tape
Implementing Value class Value { Value create(Token. Source src) { } void increase(Value v) { } void multiply(Number n) { } void print() { } }
Implementing Value: constructor class Value { constructor(Token. Source src) { to src: get String integer. Part to src: get String fraction to fraction: contains / ? if no to src: put back String fraction // just use integer. Part else // use integer. Part and fraction }. . . }
Implementing Value: other methods class Value { Value create(Token. Source src) {. . . } void increase(Value v) { // defer } void multiply(Number n) { // defer } void print() { // defer } STATE: ? ? ? }
Class Summary Completed: – – – Portfolio Holding Ticker. Tape Stock. Quote Value (partially) Yet To Complete: – – Token. Source Collection Number Stock. Name
Details of Remaining Classes: • Token. Source — constructor – get String – put back String, given String NEW ! • Collection— constructor – add –. . . some way of iterating … • Number— constructor • Stock. Name— constructor – is Match? given another Stock. Name
NEXT STEP: And so on … (I'm tired now— aren't you? )
- Slides: 89