TDDC74
Programmering:
Abstraktion och modellering
VT 2015
Johannes Schmidt
Institutionen för datavetenskap
Linköpings universitet
Lecture 9
Mutable structres, ADTs, OOP
• Abstract data types: queue, stack
• Mutable pairs, lists: singly / doubly linked list
• Object Oriented Programming (OOP) in Racket
• SICP-Book chapter: 3
An abstract data type: Stack
Think of a stack as a
pile of books
(items):
TOS: Top Of Stack.
An abstract data type: Stack
ADT Stack
Methods:
•push
: put a given item on the stack. This item is then the new TOS.
•pop
: remove the TOS-item and return it.
Optional methods:
•size
: determine the number of elements currently in the stack.
•empty?
: check whether the stack is empty.
An abstract data type: Queue
Think of a queue as a
queue of people
(items):
An abstract data type: Queue
ADT Queue
Methods:
•enqueue
: put a given item into the queue, at the rear.
•dequeue
: remove an item from the queue, at the front.
Optional methods:
•size
: determine the number of elements currently in the queue.
•empty?
: check whether the queue is empty.
How to implement
a stack, a queue?
Singly linked list
Doubly linked list
A doubly linked list with insertion and extraction at both
ends can be used to implement both, stack and queue
push
pop
enqueue
dequeue
- insert at front
- extract at front
- insert at rear
- extract at front
How to implement
singly / doubly linked lists?
Singly linked list
Easy: take on ordinary list
Doubly linked list
Easy: create a triple-object with selectors left, middle, right
E.g.
(define (make-triple left middle right)
Is a programming paradigm.
Idea: every problem can be described by objects and their
interactions / relations. This helps creating abstractions
and achieving encapsulation.
Therefore: in order to solve a problem, break it down into
subproblems, by identifying objects and how they interact
with and relate to each other.
Game Pac-Man
Scenario: Pac-Man goes through a
labyrinth, eats pellets and has to avoid
being eaten/attacked by enemies.
Identify Objects:
• Pac-Man
• Pellet
• Enemy
• Power pellet
• …
OOP Example
Source: http://en.wikipedia.org/wiki/Pac-ManRelations between Objects:
• Pac-Man eats Pellets
• Enemy eats/attacks Pac-Man
• Pac-Man eats Power pellet
• Pac-Man eats Enemy if eaten
recently Power pellet
• …
OOP Example
Is a programming paradigm.
Idea: every problem can be described by objects and their
interactions / relations.
Relations between objects indicate what different
properties the different objects should have.
These properties are realized via
fields
(variables/data)
and
methods
(procedures):
Every object has its own fields and methods!
Some fields of some Objects:
Pac-Man:
•
Lifes (0-3)
•
Score (0-1000000)
•
State: recently Power pellet eaten?
•
…
Enemy:
•
Color
•
State: currently eatable or not?
•
Direction
•
Speed
•
…
OOP Example
Some methods of some Objects:
Pac-Man:
•
(eat-enemy enemy)
•
(reduce-life amount)
•
(eat-pellet pellet)
•
(die)
•
…
Enemy:
•
(eat-Pac-Man)
•
(change-eatable-state value)
•
(speed-up)
•
(die)
•
…
OOP Example
Source: http://en.wikipedia.org/wiki/Pac-ManGame Pac-Man
Observation
:
some objects will occur just once, others several
times
Occurrences of Objects:
•
1x Pac-Man
•
Nx Pellet
•
4x Enemy
•
4x Power pellet
OOP Example
Source: http://en.wikipedia.org/wiki/Pac-ManGame Pac-Man
Observation
:
some objects will occur just once, others several
times
Occurrences of Objects:
•
1x Pac-Man
•
Nx Pellet
•
4x Enemy
•
4x Power pellet
Solution:
Classes
!
OOP Example
Source: http://en.wikipedia.org/wiki/Pac-ManA
Class
can be considered as a model for objects that
share the
same properties
, but are still
different
individuals
.
If we have a
class definition
, we can then create an
object from that class.
This process is called
instantiating
.
For this purpose every class provides a
constructor
.
Game Pac-Man
Classes for Pac-Man:
•
Pac-Man
•
Pellet
•
Enemy
•
Power-pellet
Then
instantiate
•
One object of Pac-Man
•
Many objects of Pellet
•
Four objects of Enemy
•
Four objects of Power-pellet
OOP Example
A
Class
can be considered as a model for objects that share the
same properties
, but are still
different individuals
.
What if we have similar classes that share a lot of common
properties but are not exactly the same?
Solution
: We can
derive
or
inherit
a class from another.
Via
Inheritance
we obtain a
derived class
, or a
subclass
.
Think of this as taking a copy of a class, and then modifying this
copy according to our needs.
Game Pac-Man
Similar classes for Pac-Man:
•
Pellet
•
Power-pellet
For instance make Power-pellet a subclass of
Pellet, i.e. treat a Power-pellet as a special case
of a Pellet.
Alternatively: Have a common superclass, call it
General-pellet
. Then derive once an
Ordinary-pellet
and once a
Power-pellet
.
OOP Example
(define (make-pac-man lifes score pp-eaten) ; three fields
(define (dispatch message . args) ; define different methods (cond ((eq? message 'eat-enemy)
(if pp-eaten
(void) ; details to be implemented 'not-possible))
((eq? message 'reduce-life)
(set! lifes (- lifes (car args)))) ((eq? message 'eat-pellet)
(set! score (+ score 1))) ((eq? message 'die)
(void)) ; details to be implemented ((eq? message 'say-hello)
(printf "Hi I am a happy pac-man with ~a lifes\n" lifes))
(else '(unkown message))))
dispatch)
OOP in Racket - simple
(define (make-pac-man lifes score pp-eaten) ; three fields
(define (dispatch message . args) ; define different methods (cond ((eq? message 'eat-enemy)
(if pp-eaten
(void) ; details to be implemented 'not-possible))
((eq? message 'reduce-life)
(set! lifes (- lifes (car args)))) ((eq? message 'eat-pellet)
(set! score (+ score 1))) ((eq? message 'die)
(void)) ; details to be implemented ((eq? message 'say-hello)
(printf "Hi I am a happy pac-man with ~a lifes\n" lifes))
(else '(unkown message))))
dispatch)
; create a Pac-Man: instantiate
(define my-pac-man (make-pac-man 3 0 #f))
; call some methods
(my-pac-man 'say-hello)
(my-pac-man 'reduce-life 1) (my-pac-man 'say-hello)
Output:
Hi I am a happy pac-man with 3 lifes Hi I am a happy pac-man with 2 lifes
(define Pac-Man% (class object%
; fields (variables/data)
(init-field lifes score pp-eaten)
(super-new) ; superclass initialization (define/public (eat-enemy enemy) ; method
(if pp-eaten
(void) ; details to be implemented 'not-possible))
(define/public (reduce-life amount) ; method (set! lifes (- lifes amount)))
(define/public (eat-pellet pellet) ; method (set! score (+ score 1)))
(define/public (die) ; method (void)) ; details to be implemented (define/public (say-hello)
(printf "Hi I am a happy pac-man with ~a lifes\n" lifes))))
(define Pac-Man% (class object%
; fields (variables/data)
(init-field lifes score pp-eaten)
(super-new) ; superclass initialization (define/public (eat-enemy enemy) ; method
(if pp-eaten
(void) ; details to be implemented 'not-possible))
(define/public (reduce-life amount) ; method (set! lifes (- lifes amount)))
(define/public (eat-pellet pellet) ; method (set! score (+ score 1)))
(define/public (die) ; method (void)) ; details to be implemented (define/public (say-hello)
(printf "Hi I am a happy pac-man with ~a lifes\n" lifes))))
OOP in Racket
; create a Pac-Man: instantiate
(define my-pac-man (make-object Pac-Man% 3 0 #f))
; call some methods
(send my-pac-man say-hello)
(send my-pac-man reduce-life 1) (send my-pac-man say-hello)
Output:
Hi I am a happy pac-man with 3 lifes Hi I am a happy pac-man with 2 lifes
(define General-pellet% (class object%
; fields (variables/data) (init-field color position)
(super-new) ; superclass initialization (define/public (get-type) ; method
'general)))
(define Ordinary-pellet% (class General-pellet%
(super-new) ; superclass initialization (define/override (get-type) ; method
'ordinary)))
(define Power-pellet%
(class General-pellet%
(super-new) ; superclass initialization (define/override (get-type) ; method
'power)))
(define General-pellet% (class object%
; fields (variables/data) (init-field color position)
(super-new) ; superclass initialization (define/public (get-type) ; method
'general)))
(define Ordinary-pellet% (class General-pellet%
(super-new) ; superclass initialization (define/override (get-type) ; method
'ordinary)))
(define Power-pellet%
(class General-pellet%
(super-new) ; superclass initialization (define/override (get-type) ; method
'power)))
OOP in Racket - Inheritance
We inherit from object%
This is a special inbuilt base class
We inherit from General-pellet%
(define General-pellet% (class object%
; fields (variables/data) (init-field color position)
(super-new) ; superclass initialization (define/public (get-type) ; method
'general)))
(define Ordinary-pellet% (class General-pellet%
(super-new) ; superclass initialization (define/override (get-type) ; method
'ordinary)))
(define Power-pellet%
(class General-pellet%
(super-new) ; superclass initialization (define/override (get-type) ; method
'power)))
OOP in Racket - Overriding
We inherit ALL fields and methods.
That is:
- no need to redefine fields or methods - if we want to change a method, we need
(make-object <Class> <list of init-values>)
(define my-pac-man
(make-object Pac-Man% 3 0 #f))
; Alternatively:
(new <Class> [varname1 value1] [varname2 value2] ...)
(define my-pac-man
(new Pac-Man%
[lifes 3]
[score 0]
[pp-eaten #f]))
From inside the class definition you call methods as usual.
From outside special syntax is provided:
(send <object> <method-name> <list of parameters>)
; e.g.:
(send my-pac-man say-hello)
(send my-pac-man reduce-life 1)
(send my-pac-man say-hello)
(define Pac-Man%
(class object%
; init-fields, i.e. values MUST
; be provided during instantiation
(init-field lifes score pp-eaten)
; ordinary fields, i.e. values must be provided
; right here
(field [color 'red] [more-stuff 'hmblhmbl])
...
From inside the class definition you access fields as usual variables.
From outside special syntax is provided:
(get-field <field-name> <object-name>)
(set-field! <field-name> <object-name> value)
E.g.
(define my-pac-man (make-object Pac-Man% 3 0 #f))
(get-field color my-pac-man)
(set-field! color my-pac-man 'green)
But
: avoid setting fields this way. Better provide your own
methods to change the values of fields.
(define Pac-Man%
(class object%
; public
fields (visible/accessible from outside)
(init-field lifes score pp-eaten)
(field [color 'red] [more-stuff 'hmblhmbl])
; private
fields (not visible from outside)
(define internal-value 11439)
; public
method (visible/accessible from outside)
(define/public (eat-enemy enemy) ; method
(if pp-eaten
(void) ; details to be implemented
'not-possible))
; private
method (not visible from outside)
(define (do-some-stuff parameter1)
...)
OOP in Racket – Visibility
object, class
field, method
inherit, derive, extend
subclass, superclass
override
Remember: use OOP in order to create abstractions and to
achieve encapsulation (hide implementation details).
Therefore: keep as much as possible private, so it is not
visible to the outside.
Expose to the outside only what is absolutely necessary.
Provide public methods to manipulate variables/fields, do not