230 likes | 251 Views
Explore the concepts of inheritance, subclassing, and substitutability in Java and C++ with examples and explanations. Learn about subclassing taxonomy and Liskov Substitutability Principle.
E N D
Inheritance Type/Subtype Relationship
Inheritance • Idea: An object B of one type, termed child class, inherits from another object A of another type, termed parent class, if B can access the data and methods of A • Loosely speaking, we can also say that the child class inherits from the parent class • In Java every class inherits from the Object class, i.e. Object is parent to every class
The Class Object • Extends any class, by definition • Has the general methods • equals()--meaning this and its parameter have the same content • getClass()--returns the class of the object that invokes it, e.g. • if (X.getClass()==IdTree.class) ... • hashCode()--computes the hash value of a key • toString()--converts the class to a string
Interfaces • Inheritance is also employed here • But interfaces inherit specification • Classes inherit code (and data) • Thus classes derived from some abstract class will share an interface (proper inheritance) • Inheritance of interfaces sometimes called subtyping • An object’s class indicates how the object is implemented • An object’s type refers to its interface
Inheritance: Class vs Interface • Class: An object’s implementation is given in terms of another’s implementation • Interface (subtyping): One object can be used in place of another • C++ and Java use both types of inheritance • Smalltalk uses only class inheritance • No subtyping, because variable types are not declared • Instances of any class can be assigned to a variable as long as those instances support the operations performed on the variable’s operations
Subclass, Subtype & Substitutability • Subclass: Refers to the way of deriving, or inheriting, one class from another, i.e. in Java by the keyword extends • There are various heuristics to subclassing • These are not recognizable from the program source, but rather from the kind of subclassing being implemented
Subclassing Taxonomy • Specialization: the is_a relation. This is also the subtype relation, e.g. Physics is_a Science, Putin is_a Russian • Composition: the has_a relation. E.g. a human has_a (n) arm. • Specification: Parent has abstract methods that specify the behavior of the subclass • public MyGUI extends JFrame • Most ideal type of inheritance
Sublassing Taxonomy • Construction:Just a trick, because there is no real relation between the class and its subclass (use the parent’s behavior) • Use a Vector to implement a Stack: class Stack extends Vector{ public void push(Object item) addelement(item);} public boolean empty(){return isEmpty():}
Subclassing Taxonomy • Generalization: generalize the behavior of the parent (the opposite of specialization). • If you implement a background color Black&White and use this to define a BWWindow class, you generalize if you derive a ColorWindow from it. • Better: subclass the other way round
Subclassing Taxonomy • Extension: Add completely new behavior in the child. Add new functionality not in the parent • E.g. public class Properties extends Hashtable • Use the parent Hashtable to store and retrieve, but also define a new method, e.g.: public synchronized void load(InputStream in) throws IOException;
Subclassing Taxonomy • Limitation: If you do not have access to the parent, override the irrelevant methods, i.e. the subclass is a restriction of the parent class • Of questionable value • E.g. if you wanted to use Vector to implement a Set, override the elementAt(int index) method, since it is irrelevant • Can’t do this in this case anyway (method is final)
Subclass, Subtype and Substitutability • Substitutability:When can one type be used in place of another? What does this mean? • E.g. in Pascal: • Can Complex and Vector be used interchangeably in a program? • In Pascal these are distinct type: type equivalent, but not type identical type Cpmplex = record x:real; y:real end; type Vector = record x:real; y:real end;
Liskov Substitutability Principle • Principle (Liskov): If for each object O1 of type S there is an object O2 of type T such that for all programs P defined in terms of T the behavior of P is unchanged where O1 is substituted for O2 then S is a subtype of T, or S can be substituted for T • This means: if you use O1 instead of O2 in Pthere is no observable change from running P with O2
Budd’s Version • Instances of the subclass must possess all data fields associated with the parent class • Instances of the subclass must implement, through inheritance at least, all functionality defined forthe parent class • Thus, an instance of a child class can mimic the behavior of the parent class and should be indistinguishable from an instance of the parent class if substituted in a similar situation
Remarks • This is a test for determining substitutability • Note the removal of the overridden clause • Note the no observable behavior!!
Example • Write some Java code to implement a typical bank account as given by the class CurrentAccount. Nothing special here. • Now define another account SpecialCurrentAccount by extending CurrentAccount that pays more interest, but requires that the account be opened for longer than the default period
CurrentAccount public class CurrentAccount{ protected int balance; protected int period; public CurrentAccount(int balance, int period){ this.balance = balance; this.period = period;} public boolean openAccount(int balance){ this.balance = balance;} public boolean closeAccount{ if (balance > 0) return true; else return false;} public int getBalance(){return this.balance;}
public void setBalance(int balance){ this.balance = balance:} public int getPeriod(){return this.period;} public void setPeriod(int period){ this.period = period; } }
SpecialCurrentAccount public class SpecialCurrentccount extends CurrentAccount{ private int defaultPeriod = 6; public SpecialCurrentAccount(int balance, int period}{ super(balance, period);} public boolean closeAccount(){ if (balance>0 && period>defaultPeriod) return true; else return false;} public int getDefaultPeriod(){ return this.defaultPeriod:} public void seDefaultPeriod(int defaultPeriod){ this.defaultPeriod = defaultPeriod;}
AccountTest public class AccountTest{ public void closeAnAccount(CurrentAccount ac){ System.out.println(“Account close result: ac.closeAccount()): } }
Now Close 2 Accounts • One is to be normal and the other special: public static void main(String[] args){ AccountTest test =new AccountTest(); CurrentAccount ac = new CurrentAccount(100,2); SpecialCurrentAccount sac = new SpecialCurrentAccount (200,5); test.closeAnAccount(ac); test.closeAnAccount(sac); }
Result • Liskov Substitution Principle is violated! • If the bank customer uses a SpecialCurrentAccount where a CurrentAccount is expected, the customer is in for a surprise • Big problem: the outcome is only predictable by examining the code • Way out: use an abstract base class:
Account +closeAccount:bool CurrentAccount SpecialCurrentAccount +closeAccount:bool +closeAccount:bool