SYSC 3100 System Analysis and Design Class Diagrams






























- Slides: 30

SYSC 3100 System Analysis and Design Class Diagrams Generalization hierarchies substitutability SYSC 3100 - System Analysis and Design 1

Objectives • Generalization: When to use it and when not to. • Identify the types of generalization: – – – Interface (the good) Implementation (the potentially bad) Extension Restriction (the definitely bad!) Convenience (the ugly) • Use of delegation versus inheritance. (you have seen this before). • An introduction to the Liskov Substitution Principle. This lecture is probably the most important one of all when it comes to good Object-Oriented design!!! SYSC 3100 - System Analysis and Design 2

Introduction • Generalization is a relationship between a more general element and a more specific element, where the more specific element is entirely consistent with the more general element but contains more information. • The two elements obey the substitutability principle – we can use the more specific element where the more general element is expected without breaking the system. • Generalization is a much stronger type of relationship than association. • Generalization implies the very highest level of dependency and therefore coupling between two elements. SYSC 3100 - System Analysis and Design 3

Inheritance and generalization • Generalization – Useful and powerful concept but many problems due to intricacies of inheritance – States that the interface of the subclass must include all (public and protected) properties of the superclass • Inheritance is “the mechanism by which more specific elements incorporate structure and behavior defined by more general elements” • Inheritance is not generalization – the former is the programming language mechanism through which proper generalization can be implemented. • Benefits of generalization arise from the substitutability principle – Subclass object can be used in place of a superclass object in any part of the code where the superclass object is accessed • However, and unfortunately, the inheritance mechanism may be used in a way that defeats the benefits of the substitutability principle SYSC 3100 - System Analysis and Design 4

Inheritance vs encapsulation • Encapsulation – Demands that object's attributes be only accessible through the operations in the object’s interface – Is orthogonal to inheritance • Inheritance compromises encapsulation by allowing subclasses to directly access protected attributes – This can lead to serious problems, i. e. , no substitutability SYSC 3100 - System Analysis and Design 5

Overriding and callbacks • Subclass can inherit the – Method signature and implementation and introduces no changes to the implementation – Implementation and include it (call it) in its own method with the same signature – Implementation and then completely override it with a new implementation with the same signature – Implementation that is empty (i. e. the method declaration is empty) and then provide the implementation for the method – Method signature only and then provide the implementation for the method SYSC 3100 - System Analysis and Design 6

Interface inheritance • Interface inheritance: subtyping, type inheritance – This is a “harmless” form of inheritance – A subclass inherits attribute types and operation signatures (operation names plus formal arguments) – A subclass is said to support a superclass interface – The implementation of inherited operations is deferred until later – The interfaces are normally declared through an abstract class • We can say – with one proviso – that an interface is an abstract class • The proviso is that an abstract class can provide partial implementations for some operations whereas a pure interface defers the definition of all operations SYSC 3100 - System Analysis and Design 7

Interface inheritance Computer - computer_name : String + get. Conf() Configured. Computer Standard. Computer - configured_price : Currency + get. Conf() - standard_price : Currency + get. Conf() SYSC 3100 - System Analysis and Design 8

Realization relationship An alternative way of representing the interface inheritance - with a “lollypop” symbol to indicate the supported interface. The “lollypop” relationship from a subclass (concrete class) to an abstract class is formally called the realization relationship. SYSC 3100 - System Analysis and Design 9

Implementation inheritance • Generalization can be used (deliberately or not) to imply code reuse and it is then realized by an implementation inheritance • A very powerful, sometimes dangerously powerful, interpretation of generalization – It is also the “default” interpretation of generalization – Combines the superclass properties in the subclasses and allows overriding them with new implementations, when necessary – Allows sharing of property descriptions, code reuse, and polymorphism SYSC 3100 - System Analysis and Design 10

Extension inheritance • Inheritance as an incremental definition of a class • A subclass is-kind-of superclass • This is a proper use of implementation inheritance • The overriding of properties should be used with care. It should only be allowed to make properties more specific (e. g. to produce additional outputs, to make implementations of operations more efficient), not to change the meaning of a property. SYSC 3100 - System Analysis and Design 11

Restriction inheritance • Inheritance as a restriction mechanism whereby some inherited properties are suppressed in the subclass • This is a problematic use of inheritance • A superclass object can still be substituted by a subclass object provided that whoever is using the object is aware of the suppressed properties SYSC 3100 - System Analysis and Design 12

Convenience inheritance • When two or more classes have similar implementations, but there is no taxonomic relationship between the concepts represented by the classes • One class is selected arbitrarily as an ancestor of the others • This is an improper use of inheritance SYSC 3100 - System Analysis and Design 13

Convenience inheritance • When inheritance is used for the purpose of reusing code but does not implement a proper generalization • Example: Set implemented by inheriting from Hashtable • Convenience inheritance results in operations being inherited but meaningless in the context of the subclass. This is potentially dangerous as it can create confusion when one modifies or uses the subclass • Convenience inheritance should be avoided and substituted with Delegation • A class is said to delegate to another class if it implements an operation by merely resending a message to another class. SYSC 3100 - System Analysis and Design 14

Myset Example Object design model before transformation Object design model after transformation Hashtable put(key, element) get(key): Object contains. Key(key): boolean contains. Value(element): boolean table 1 1 My. Set put(element) contains. Value(element): boolean SYSC 3100 - System Analysis and Design 15

Myset Java Implementation /* Implementation of My. Set using inheritance */ class My. Set extends Hashtable { /* Constructor omitted */ My. Set() { } void put(Object element) { if (!contains. Key(element)){ put(element, this); } } boolean contains. Value(Object element){ return contains. Key(element); } /* Other methods omitted */ } SYSC 3100 - System Analysis and Design /* Implementation of My. Set using delegation */ class My. Set { Hashtable; My. Set() { table = new Hashtable(); } void put(Object element) { if (!table. contains. Key(element)){ table. put(element, this); } } boolean contains. Value(Object element) { return (table. contains. Key(element)); } /* Other methods omitted */ } 16

Stack with Inheritance v. Delegation • Implementing a Stack class by reusing a Linked. List class • Our Stack class contains the following: – push() to add an object to the top of the stack – peek(): Object to return the object on the top of the stack. – is. Empty(): boolean to return true if there are no objects on the stack. – pop(): Object to remove an object from the top of the stack and return it. • Now, the Linked. List class contains among others the following four messages that we can reuse: – add. Element() which adds an object to the end of the list – last. Element(): Object which returns the object at the end of the list. – number. Of. Element(): int which returns the number of objects in the list. – remove. Last. Element() which removes the object at the end of the list. SYSC 3100 - System Analysis and Design 17

Implementing the stack using inheritance • Let say we choose to make our Stack class a subclass of Linked. List as shown. Then we have the Java code: Public class Stack extends Linked. List { public void push(Object o) { add. Element(o); } public Object peek() { return last. Element(); } public boolean is. Empty() { return number. Of. Elements() == 0; } public Object pop() { Object o = last. Element(); remove. Last. Element(); return o; } We can now create a stack object } Stack a. Stack = new Stack(); and use it: a. Stack. push(new Plate(“Wedgwood”)); … SYSC 3100 - System Analysis and Design 18

Stack with inheritance cont. • There is potentially serious problem with this way of implementing Stack. • Since Stack is a subclass of Linked. List, all other Linked. List messages are also available to stack objects since a subclass is expected to offer at least the same services as its superclass. • Now, the problem is that if Linked. List has messages such as first. Element that a client would still be able to use and that are inappropriate for Stack e. g. Person a. Person = new Person() a. Person. take(a. Stack. first. Element()); • This piece of code means that the client of a. Stack has just removed the element from the bottom of the stack – something that the client is not supposed to be able to do. SYSC 3100 - System Analysis and Design 19

Stack using Delegation • In this case, the behaviour of encapsulated Linked. List is used by Stack but none of the extra Linked. List behaviour is exposed to Stack clients. In other words a. Stack delegates its behaviour to a. Linked. List. Public class Stack { private Linked. List list; public Stack() { list = new Linked. List(); } public void push(Object o) { add. Element(o); } public Object peek() { return last. Element(); } public boolean is. Empty() { return number. Of. Elements() == 0; } public Object pop() { Object o = last. Element(); remove. Last. Element(); return o; } } The following does not work : a. Person. take(a. Stack. firstelement()); SYSC 3100 - System Analysis and Design 20

Liskov Substitution Principle • Liskov substitution principle states that, if a client code uses the methods provided by a superclass, then developers should be able to add new subclasses without having to change the client code. • This principle defines the notions of generalization / specialization in a formal manner • Class S is correctly defined as a specialization of class T if the following is true: a client method written in terms of superclass T must be able to use instances of S without knowing whether the instances are of S or T. • S is a said to be a subtype of T • Instances of a subclass can stand for instances of a superclass without any effect on client classes • Any future extension (new subclasses) will not affect existing clients. • Any future extension (new subclasses) will not affect parent methods SYSC 3100 - System Analysis and Design 21

Lack of Substitutability class Rectangle : public Shape { private: int w, h; public: virtual void set_width(int wi) { w=wi; } virtual void set_height(int he) { h=he; } } void foo(Rectangle *r) { r->set_width(5); r->set_height(4); assert((r->get_width()*r->get_height()) ==20); } class Square : public Rectangle { public: void set_width(int w) { Rectangle: : set_height(w); Rectangle: : set_width(w); } void set_height(int h) { set_width(h); } } SYSC 3100 - System Analysis and Design 22

Rules • Signature Rule: The subtypes must have all the methods of the supertype, and the signatures of the subtypes’ methods must be compatible with the signatures of the corresponding supertypes methods • In Java, this is enforced as the subtype must have all the supertype methods, with identical signatures except that a subtype method can have fewer exceptions (compatibility stricter than necessary here) • Method Rule: Calls on the subtype methods must “behave like” calls to the corresponding supertype methods. • Property Rule: The subtype must preserve the invariant of the supertype. SYSC 3100 - System Analysis and Design 23

Method Rule • S is a subtype of T • If methods T: : m() and S: : m() (overriding) have preconditions Pr. C 1 and Pr. C 2, respectively, Pr. C 1 => Pr. C 2 • The precondition is weakened • If methods T: : m() and S: : m() (overriding) have postconditions Po. C 1 and Po. C 2, respectively, Po. C 2 => Po. C 1 • The postcondition is strengthened SYSC 3100 - System Analysis and Design 24

Int. Set public class Int. Set { private Vector els; /// the elements public Int. Set() {…} // Post: Initializes this. els to be empty public void insert (int x) {…} // Post: Adds x to the elements of this public void remove (int x) {…} // Post: Remove x from the elements of this public boolean is. In (int x) {…} //Post: If x is in this returns true else returns false public int size () {…} //Post: Returns the cardinality of this public boolean subset (Int. Set s) {…} //Post: Returns true if this is a subset of s else returns false } SYSC 3100 - System Analysis and Design 25

Max. Int. Set public class Max. Int. Set extends Int. Set { private int biggest; // biggest element if set not empty public max. Int. Set () {…} // call super() public max () throws Empty. Exception {…} // new method public void insert (int x) {…} // overrides In. Set: : insert() //Additional Post: update biggest with x if x > biggest public void remove (int x) {…} // overrides In. Set: : remove() //Additional Post: update biggest with next biggest element in this if x = biggest } SYSC 3100 - System Analysis and Design 26

Example Preconditions public class Linked. List {. . . /** * Adds an element to the end of the list * * PRE: element != null * * POST: this. get. Length() == old. get. Length() + 1 * && this. contains(element) == true */ public void add. Element(Object element) {. . . } SYSC 3100 - System Analysis and Design public class Set extends Linked. List {. . . /** * Adds element to this set, provided * element is not already in the set * * PRE: element != null * && this. contains(element) == false * * POST: this. get. Length() == old. get. Length() + 1 * && this. contains(element) == true */ public void add. Element(Object element) {. . . } 27

Properties Rule • All methods of the subtype (i 2) must preserve the invariant of the supertype (i 1) • The invariant of the subtype must imply the invariant of the supertype (i 2 => i 1) • Assume Fat. Set is a set of integers whose cardinality (card) is always at least 1. The constructor and remove methods ensure this. • Inv: self. card >= 1 • Thin. Set is also a set of integers but can be empty and therefore cannot be a legal subtype of Fat. Set • Inv: self. card >= 0 SYSC 3100 - System Analysis and Design 28

In. Set, Max. In. Set • Invariant of Int. Set, for any instance i : i. els != null and All elements of i. els are Integers and There are no duplicates in i. els • Invariant of Max. Int. Set, for any instance i : Invariant of In. Set and i. size > 0 and For all integers x in els, x <= i. biggest SYSC 3100 - System Analysis and Design 29

Summary • Generalization should only be used when subclassing makes sense. – All subclass objects should behave the same way as their superclass object (this is the basis of the Liskov Substitution Principle). – Beware of convenience and restriction subclassing! – Interfaces are always a good thing! • We can always make use of delegation (essentially, referencing another object via an association – this is the basis of the ‘self’ programming language. ) SYSC 3100 - System Analysis and Design 30