Purpose
Compound objects combine objects together
- A date: a year, a month, and a day
- A geographic position: latitude and longitude
- A rational number: a numerator and a denominator. An abstract data type lets us manipulate compound objects as units
- Isolate two parts of any program that uses data:
- How data are represented (as parts) (e.g. use Container.)
- How data are manipulated (as units)
Between them is the abstraction barrier.(Lec.11)
- Data abstraction: A methodology by which functions enforce an abstraction barrier between representation and use.
Constructor and Selector
A data abstraction is a set of functions that compose and decompose compound values.
- One function called the constructor puts together two or more parts into a whole (such as a rational number; also known as a fraction).
- other functions called selectors return parts of that whole (such as the numerator or denominator).
What is Data?
- We need to guarantee that Constructor and Selector functions work together to specify the right behavior
- Behavior condition: If we construct rational number x from numerator n and denominator d, then
numer(x) / denom(x)must equal n/d - Data abstraction uses selectors and constructors to define behavior
- If behavior conditions are met, then the representation is valid
You can recognize data abstraction by its behavior.
Example
# Rational arithmetic
def add_rational(x, y):
"""Add rational numbers x and y."""
nx, dx = numer(x), denom(x)
ny, dy = numer(y), denom(y)
return rational(nx * dy + ny * dx, dx * dy)
def mul_rational(x, y):
"""Multiply rational numbers x and y."""
return rational(numer(x) * numer(y), denom(x) * denom(y))
def rationals_are_equal(x, y):
"""Return whether rational numbers x and y are equal."""
return numer(x) * denom(y) == numer(y) * denom(x)
def print_rational(x):
"""Print rational number x."""
print(numer(x), "/", denom(x))
"""-----------------------Abstraction Barrier----------------------------"""
# Constructor and selectors
def rational(n, d):
"""Construct a rational number x that represents n/d."""
return [n, d]
def numer(x):
"""Return the numerator of rational number x."""
return x[0]
def denom(x):
"""Return the denominator of rational number x."""
return x[1]Things above the barrier don’t assume anything about how a rational number represent.
Things below don’t care about how a list implement, either.
Then, if we change how it is represented:
# Constructor and selectors
def rational(n, d):
"""Construct a rational number x that represents n/d."""
def select(name):
if name == 'n':
return n
elif name == 'd':
return d
return select
def numer(x):
"""Return the numerator of rational number x."""
return x('n')
def denom(x):
"""Return the denominator of rational number x."""
return x('d')It behaves just like before, so it is valid and we do not need to change anything above the barrier.