1 / 67

Lec05 Data Abstraction (Chapter 5)

Lec05 Data Abstraction (Chapter 5). Software Engineering Fall 2005. Data Abstraction. data abstraction = <objects,operations> if only objects were provided -> user would implement program in terms of the data representation -> when representation changes -> user programs have to change

Télécharger la présentation

Lec05 Data Abstraction (Chapter 5)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Lec05 Data Abstraction(Chapter 5) Software Engineering Fall 2005

  2. Data Abstraction • data abstraction = <objects,operations> • if only objects were provided -> user would implement program in terms of the data representation-> when representation changes -> user programs have to change • therefore, the user has to call the operations to access the data type-> when representation changes-> operation implementations change-> user programs stay the same

  3. 5.1 Specification of Data Abstractions • Data types are defined by interfaces & classes • <visibility> class dname {// OVERVIEW: brief description of the date type’s// behavior// constructors// specs for constructors// methods// specs for methods • }

  4. Components of Specification • OVERVIEW gives a description of the abstraction in terms of “well understood” concepts(for instance mathematical sets “{}”, union “+”…) • specifies if the type is mutable or immutable • constructors specify how new objects are created • methods specify how objects are accessed once they have been created • constructors and methods belong to objects, not classes -> no static in header

  5. Specification of mutable IntSet • public class IntSet {// OVERVIEW: IntSets are mutable, unbounded sets of integers// A typical IntSet is {x1,...,xn} • // constructorspublic IntSet ()// EFFECTS: Initializes this to be empty • // methodspublic void insert (int x)// MODIFIES: this// EFFECTS: Adds x to the elements of this, i.e. this_post = this + {x} • public void remove (int x) // MODIFIES: this// EFFECTS: Removes x from this, i.e. this_post = this - {x} • // observerspublic boolean isIn (int x) // EFFECTS: if x is in this returns true else returns false • public int size ( ) // EFFECTS: Returns the cardinality of this • public int choose ( ) throws EmptyException // EFFECTS: if this is empty, throws EmptyException else// returns an arbitrary element of this • }

  6. IntSet • Only one parameterless constructor is enough: type is mutable • Mutators insert and remove have MODIFIES clause • this_post = this after the method returns • Observers isIn, size and choose do not change the state of the object(observers are allowed to modify anything other than this, but usually don’t) • choose returns an arbitrary element of the Inset: it is underdetermined • Specification is preliminary version of the class

  7. Specification of immutable Poly (1) • public class Poly {// OVERVIEW: Polys are immutable polynomials with integer coefficients// A typical Poly is c0 + c1x + c2x^2 + c5x^5 + ... + cnx^n • // constructorspublic Poly() // EFFECTS: Initializes this to be the zero polynomial • public Poly(int c, int n) throws NegativeExponentException // EFFECTS: If n < 0 throws NegativeExponentException else// initializes this to be the Poly cx^n • // methodspublic int degree () // EFFECTS: Returns the degree of this, i.e. the largest exponent// with a non-zero coefficient. Returns 0 if this is the zero Poly • public int coeff (int d) // EFFECTS: Returns coefficient of the term of this whose exponent is d • public Poly add (Poly q) throws NullPointerException // EFFECTS: If q is null throws NullPointerException else returns // the Poly this + q • public Poly mult (Poly q) throws NullPointerException // EFFECTS: If q is null throws NullPointerException else returns // the Poly this * q

  8. Specification of immutable Poly (2) • public Poly sub (Poly q) throws NullPointerException // EFFECTS: If q is null throws NullPointerException else returns // the Poly this - q • public Poly minus () {// EFFECTS: Returns the Poly - this • }

  9. Poly • Two constructors: zero and arbitrary monomial(overloaded) • Arbitrary polynomials are created by adding and multiplying polynomials, each time creating a new Poly (type is immutable) • -> no Mutators • NegativeExponentException is unchecked • (it is easy to avoid calls with a negative exponent)

  10. Using IntSet Abstraction • public static IntSet getElements (int[] a) • throws NullPointerException {// EFFECTS: If p is null throws NullPointerException // else returns a set containing an entry for each// distinct element of a • IntSet s = new IntSet();for (int i = 0; i < a.length(); i++) { s.insert(a[i]);} • return s; • }

  11. 5.2 Using Data (Poly) Abstractions • public static Poly diff (Poly p) throws NullPointerException {// EFFECTS: If p is null throws NullPointerException// else returns the Poly obtained by differentiating p • Poly q = new Poly (); • for (int i = 1; i <= p.degree(); i++) { • q = q.add(new Poly(p.coeff(i) * i, i - 1));} • return q; • }

  12. diff & getElements • These functions are not declared in IntSet or Poly,but in another class that uses IntSet and Poly. • => if the implementation of the data abstraction changesmethods diff & getElements will continue to work correctly • => diff & getElements, if implemented incorrectlywill not affect the correctness of the abstractionnor can they break other code that uses the abstraction • but: diff & getElements may be slightly slower that if they were implemented behind the abstraction barrier

  13. 5.3 Implementing Data Abstractions • One data abstraction can have many different possible representations or reps • An implementation makes sure that the representation is initialized (constructors),used and modified (methods)correctly according to the data abstraction • A good representation allows all operations to be implemented in a reasonably simple and efficient manner (+ frequent operations must run quickly) • IntSet rep as Vector: allow duplicate elements? • -> insert will be faster-> remove will be slower-> isIn will be slower for false, faster for true

  14. Instance variables • A representation typically has a number of components • Each component is stored in an instance variable • Instance variables should be declared privateto preventa user from breaking the abstractionto allow re-implementation without breaking the user’s code • Instance variables should not be declared static(i.e. there is one of each per object) • Static variables occur once per class(equivalent to global variables in other languages)

  15. Implementation of IntSet (1) • public class IntSet {// OVERVIEW: IntSets are mutable, unbounded sets of integersprivate Vector els; // the rep • // constructorspublic IntSet() {// EFFECTS: Initializes this to be emptyels = new Vector(); } • // methodspublic void insert (int x) {// MODIFIES: this// EFFECTS: Adds x to the elements of this, i.e. this_post = this + {x}Integer y = new Integer(x);if (getIndex(y) < 0) els.add(y); } • public void remove (int x) {// MODIFIES: this// EFFECTS: Removes x from this, i.e. this_post = this - {x}int i = getIndex(new Integer(x));if (i < 0) return;els.set(i, els.lastElement());els.remove(els.size() -1);}

  16. Implementation of IntSet (2) • private int getIndex (Integer x) {// EFFECTS: if x is in this returns index where x appears else -1for (int i = 0; i < els.size(); i++) if (x.equals(els.get(i))) return i;return -1; } • public boolean isIn (int x) {// EFFECTS: if x is in this returns true else returns falsereturn getIndex(new Integer(x)) >= 0; } • public int size ( ) {// EFFECTS: Returns the cardinality of thisreturn els.size(); } • public int choose ( ) throws EmptyException {// EFFECTS: if this is empty, throws EmptyException else// returns an arbitrary element of thisif (els.size() == 0) throw EmptyException("IntSet.choose");return els.lastElement();}

  17. IntSet Implementation • rep is a single private instance variable els • constructors belong to a particular object,manipulated as implicit argument this(can be omitted to access its instance variables) • a private helper function getIndex is used to make sure there are no duplicates in the vector els • getIndex allows insert to preserve the no-duplicates condition • this condition is relied upon in size and remove

  18. Implementation of Poly (1) • public class Poly {// OVERVIEW:…private int [ ] trms;private int deg; • // constructors • public Poly() {// EFFECTS: Initializes this to be the zero polynomialtrms = new int[1]; deg = 0; } • public Poly(int c, int n) throws NegativeExponentException {// EFFECTS: If n < 0 throws NegativeExponentException else// initializes this to be the Poly cx^nif (n < 0) throw NegativeExponentException("Poly(int,int) constr");if (c == 0) {trms = new int[1]; deg = 0; return;}trms = new int[n+1];for (int i = 0; i < n; i++) trms[i] = 0;trms[n] = c;deg = n; } • private Poly (int n) {trms = new int[n+1]; deg = n;}

  19. Implementation of Poly (2) • // methods • public int degree () {// EFFECTS: Returns the degree of this, i.e. the largest exponent// with a non-zero coefficient. Returns 0 if this is the zero Polyreturn deg; } • public int coeff (int d) {// EFFECTS: Returns the coefficient of term of this with exponent dif (d < 0 || d > deg) return 0; else return trms[d]; } • public Poly sub (Poly q) throws NullPointerException {// EFFECTS: If q is null throws NullPointerException else returns // the Poly this - q;return add (q.minus()); } • public Poly minus () {// EFFECTS: Returns the Poly - this;Poly r = new (Poly(deg));for (int i = 0; i < deg; i++) r.trms[i] = - trms[i];return r; }

  20. Implementation of Poly (3) • public Poly add (Poly q) throws NullPointerException {// EFFECTS: If q is null throws NullPointerException else returns // the Poly this + qPoly la, sm;if (deg > q.deg) {la = this; sm = q;} else {la = q; sm = this;}int newdeg = la.deg; // new degree is the larger degreeif (deg == q.deg) // unless there are trailing zeros for (int k = deg; k > 0; k--) if (trms[k] + q.trms[k] != 0) break; else newdeg--;Poly r = new Poly(newdeg); // get a new Polyint i;for (i = 0; i < sm.deg && i <= newdeg; i++) r.trms[i] = sm.trms[i] + la.trms[i];for (int j = i; j <= newdeg; j++) r.trms[j] = la.trms[j];return r;}

  21. Implementation of Poly (4) • public Poly mul (Poly q) throws NullPointerException {// EFFECTS: If q is null throws NullPointerException else returns // the Poly this * qif ((q.deg == 0 && q.trms[0] == 0) || (deg == 0 && trms[0] == 0)) return new Poly();Poly r = new poly(deq + q.deg);for (int i = 0; i <= deg; i++) for (int j = 0; j <= q.deg; j++) r.trms[i+j] = r.trms[i+j] + trms[i] * q.trms[j];return r; }

  22. Poly Implementation • rep is an array storing coefficients (immutable)plus an int storing the degree (for convenience) • Note that many methods access private instance variables from other objects as well as this(methods have access to private instance variables of objects of the same class) • sub is implemented in terms of other methods • add, mul and minus use private constructor Poly(int) and initialize the new Poly themselves

  23. Alternative Poly Implementation • What if most of the terms have zero coefficients ? • Previous implementation contains mostly zeroes. • => store only the terms with non-zero coefficients • use 2 vectors: • private Vector coeffs; // the non-zero coefficients • private Vector exps; // the associated exponents • but this is awkward: Vectors have to be precisely lined up. • instead: use one vector storing both coef and exps

  24. Records • // inner classclass Pair { // OVERVIEW: a record type int coeff; int exp; Pair (int c, int n) {coeff = c; exp = n;}} • A record is simply a collection of instance variables and a constructor to initialize them. No methods. • You can declare this inside Poly as an inner class. • Do not abuse records. They are only to be used as passive storage within a full-blown data abstraction.

  25. Implementation of sparse Poly • // using two vectors • private Vector coeffs; // the non-zero coefficients • private Vector exps; // the associated exponents • public int coeff (int x) {for (int i = 0; i < exps.size(); i++) if (((Integer) exps.get(i)).intValue() == x) return ((Integer) coeffs.get(i)).intValue();return 0; • } • // using Pair records • private Vector trms; // the terms with non-zero coefficients • public int coeff (int x) {for (int i = 0; i < trms.size(); i++) Pair p = (Pair) trms.get(i); if (p.exp == x) return p.coeff;}return 0; • }

  26. 5.4 Additional Methods • In our discussion of objects, we have • ignored some methods that all objects have. • . Unless classes define these methods, they will inherit them from the Object class, which may or may not be desirable. • . We'll talk about the equals, clone, and toString methods.

  27. Other methods: equality • Two objects are equalif they are behaviorally equivalent • => it is not possible to distinguish between them using any sequence of calls to the objects • Mutable objects are equals only if they are the same objects (otherwise you can change one of them and prove they are not the same):equals inherited from Object same as == • Immutable objects are equals if they have the same state:must implement equals themselves

  28. equals for Poly • public boolean equals (Poly q) {if (q == null || deg != q.deg) return false;for (int i = 0; i < deg; i++) if (trms[i] != q.trms[i]) return false;return true; • } • public boolean equals (Object z) {if (! ( z instanceof Poly) return false;return equals ((Poly) z); • }

  29. Other methods: hashCode • int hashCode () is defined by Object • is used in hashtables to provide a unique number for each distinct object • Objects that are equal should have the same hashCode • => mutable objects do not have to define hashCode • => immutable objects have to define hashCode(otherwise they will have the same hashCode only if they are ==)

  30. Other methods: similarity • Two objects are similar if they have the same state at the moment of comparison • Weaker notion of equality: • similar immutable objects are always equal • similar mutable objects may not be equal • == is stronger than equal is stronger than similar

  31. Other methods: clone • Object clone () • makes a copy of its objectthe copy should be similar to the original • default implementation form Object simply makes a new Object and copies all instance variables (shallow copy) • this is sufficient for immutable objectsclone() is made accessible by declaring: public myClass implements Cloneable {… • mutable objects should implement their own cloning operation (using a deep copy)

  32. clone for IntSet • private IntSet (Vector v) { • els = v; • } • public Object clone () {return new IntSet((Vector)els.clone()); • }

  33. Other methods: toString • String toString()should return a String showing the type and current state of the object • Default implementation from Object shows type and hashCode • => not very informative • => objects should implement toString themselves

  34. toString for IntSet • public String toString () {if (els.size () == 0) return “IntSet: { }”;String s = “IntSet: {“ + els.elementAt(0).toString( );for (int i = 1; i < els.size( ); i++) s = s + “ , “ + els.elementAt(i).toString( );return s • + “}”; • }

  35. 5.5 Aids to Understanding Implementations • Abstraction function: • shows how the representation maps to the data abstraction • justifies the choice of representation • Representation invariant: • captures the common assumptions on which the implementations are based • allows the implementation of one method to be read in isolation of all others • for instance: why can IntSet size() return the size of els ? Because there are no duplicates in els

  36. IntSet {1,2} {7} els [1,2] [2,1] [7] Abstraction functions • AF: C -> A • the abstraction function AF maps a concrete state Cto an abstract state A • abstraction functions are usually many-to-one

  37. Abstraction function for IntSet • Abstraction functions are defined informally, so the range is hard to define. Instead we show a typical example: • // A typical IntSet is {x1,…xn} • // The abstraction function is • // AF(c) = {c.els[i].intValue | 0 <= i < c.els.size} • {x| p(x)} • describes the set of all x such that the predicate p(x) is true

  38. Abstraction function for Poly • // A typical Poly is c0 + c1x + c5x^5 + ... + cnx^n • // The abstraction function is • // AF(c) = c0 + c1x + c5x^5 + ... + cnx^n • // where • // ci = c.trms[i] if 0 <= i < c.trms.size • // = 0 otherwise

  39. The representation invariant • Type checking ensures that when an object this is constructed or called with a method, it belongs to the class • However, not all objects of a class are legitimate representations of abstract objects • The statement of a property that all legitimate objects satisfy is called a representation invariant or rep invariant • I: C -> boolean • is predicate that holds true for legitimate objects

  40. Representation invariant of IntSet • // The rep invariant is • // c.els != null && • // for all integers i.c.els[i] is an Integer && • // for all integers i,j.(0 <= i < j < c.els.size => • // c.els.[i].intValue != c.els.[j].intValue) • or more informally: • // The rep invariant is • // c.els != null && • // all elements of c.els are Integers && • // there are no duplicates in c.els

  41. Alternative Representation for IntSet • private boolean[100] els; • private Vector otherEls; • private int sz; • for integers in the range 0..99 we record membership by storing true in els[i] • integers outside this range are stored as before • the number of elements is stored in sz

  42. Abstraction function • // The abstraction function is • // AF(c) = {c.otherEls[i].intValue | • // 0 <= i < c.otherEls.size} • // + • // { j | 0 <= j < 100 && c.els[j] } • the set is the union of elements in otherEls and the indexes of true elements in els

  43. Representation invariant • // The rep invariant is • // c.els != null && • // c.otherEls != null && • // c.els.size = 100 && • // all elements in c.otherEls are Integers && • // all elements in c.otherEls are not in range 0..99 && • // there are no duplicates in c.otherEls && • // c.sz = c.otherEls + (count of true entries in c.els)

  44. Helper function in rep invariant • // c.sz = c.otherEls + (count of true entries in c.els) • can be rewritten as: • // c.sz = c.otherEls.size + cnt(c.els, 0) • // where cnt(a,i) = if i >= a.size then 0 • // else if a[i] then 1+ cnt (a, i+1) • // else cnt (a, i)

  45. Representation invariant of Poly • // The rep invariant is • // c.trms != null && • // c.trms.length >= 1 && • // c.deg = c.trms.length - 1 && • // c.deg > 0 => x.trms[deg] != 0

  46. Implementing abstraction functions • Instead of giving the abstraction function as a comment, it may also be implemented as a method • The abstraction function explains the interpretation of the rep. It maps the state of each legal representation to the abstract object it is intended to represent. It is implemented by the toString method • => if two different representations map to the same abstract object they should have the same toString result

  47. Implementing representation invariants • The representation invariant defines all the common assumptions that underlie the implementations of a type’s operations. It defines which representations are legal by mapping each representation object to either true (if its rep is legal) or false (if its rep is not legal. The method that checks the representation invariant is called repOk: • public boolean repOk ( ) • // EFFECTS: Returns true if the rep invariant// holds for this;// otherwise returns false

  48. repOk for Poly • public boolean repOk ( ) { • if (trms == null || deg != trms.length - 1 || trms.length == 0) return false; • if (deg == 0) return true; • return trms[deg] != 0; • }

  49. repOk for IntSet • public boolean repOk ( ) { • if (els == null) return false; • for (int i = 0; i < els.size ( ); i++) { Object x = els.get(i); if (! (x instanceof Integer)) return false; for (int j = i + 1; j < els.size ( ); j++) if (x.equals(els.get(j))) return false; • } • return true; • }

  50. uses of repOk • repOk can be used during testing to check whether an implementation is preserving the rep invariant • repOk can be used in methods and constructors to practice defensive programming (throw a FailureException if the rep invariant does not hold) • Only constructors and methods that modify the representation need to check repOk: • add, mul, minus, but not sub or coeff in Poly • insert and remove in IntSet

More Related