Top Banner
1 Inheritance & Delegation
32

1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

Dec 20, 2015

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

1

Inheritance & Delegation

Page 2: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

2

Our Starting Point

• We know OOP• Objects are instances of classes • Overriding• We have used inheritance

Page 3: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

3

Terminology

• Per class– Forge: Signatures of accessible constructors– Mill: Bodies of constructor– Protocol: Signatures of accessible fields, methods– Behavior: Bodies of methods– Structure: Memory layout of an object

• Per object– State: Values held by fields of an object– Identity: Distinguishes two objects

Page 4: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

4

The Two Effects of Subclassing

• Code Reuse– code of superclass is available in subclass

• Polymorphism– Instances of subclass can masquerade as instances of

superclass

• Next slide:– [Reuse] No upcasting of KShortestPathsIterator– [Reuse] No upcasting of ArrayList– [Polymorhism] PathWrapper is added to

ArrayList<GraphPath>

Page 5: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

5public List<GraphPath<V, E>> getPaths(V endVertex) { KShortestPathsIterator<V, E> iter = new KShortestPathsIterator<V, E>(graph, startVertex, endVertex, nPaths);

for(int passNumber = 1; (passNumber <= nMaxHops) && iter.hasNext(); passNumber++) iter.next();

List<RankingPathElement<V, E>> list = iter.getPathElements(endVertex); if (list == null) return null;

ArrayList<GraphPath<V, E>> pathList = new ArrayList<GraphPath<V, E>>(); for (RankingPathElement<V, E> element : list) pathList.add(new PathWrapper(element));

return pathList;} // Taken from: org.jgrapht.alg.KShortestPaths

Page 6: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

6

Polymorphic Messages• Same message will trigger different reactions

– Very powerful mechanism

• Previously (no polymorphic messages)for(Product x : products) { double price = x.fixedPrice ? x.price : x.price*0.7; System.out.println("New price is " + price);}

• W/ polymorphic messagesfor(Product x : products) { double price = x.discountPrice(0.7); ..}• Implementing classes: Product, FixedPriceProduct

Page 7: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

7class Product {

double price;

public Product(double p) { price = p; }

public double discountPrice(double factor) {

return factor * price;

}

}

class FixedPriceProduct extends Product {

public FixedPriceProduct(double p) { super(p); }

public double discountPrice(double factor) {

return price;

}

}

Page 8: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

8

<difficulties>

Page 9: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

9

Subclass can Break Superclass

public class Range { protected int b, e;

void setBegin(int n) { b = n; } void setEnd(int n) { e = n; } void shift(int n) { setBegin(b + n); setEnd(e + n); }}

public class PositiveRange { private void check() { if(e < b) throw new RuntimeException(); }

void setBegin(int n) { super.setBegin(n); check(); } void setEnd(int n) { super.setEnd(n); check(); }}

Page 10: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

10

Semantic Mismatch

class Product {

double price, cost;

Product(double p, double c) { price = p; cost = c; }

void getProfit() { return price – cost; }

double getPrice() { return p; }

void setPrice(double p) { price = p; }

}

class FixedPriceProduct extends Product {

FixedPriceProduct(double p, double c) { super(p, c); }

void setPrice(double p) { } // Price never changes!

}

Page 11: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

11

Semantic Mismatch (cont.)

class Store {

Product[] products;

void increaeProfit(double factor) {

for(Product p : products) {

double diff = factor * p.getPrice();

p.setPrice(p.getPrice() + diff);

}

}

// Problem: increaseProfit(0.1) will not always lead

// to 10% increase in profit !!

Page 12: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

12

Semantic Mismatch: Summary

• The author of increaseProfit expected setPrice to change the price of the product– This is true for class Product– This is not true for FixedPriceProduct

• Sometimes one can find a neutral implementation– Provides the semantics the caller expects– Does not break the invariants of the class – E.g., the discountPrice() method– (Sadly, this is not the case here)

• The standard solution: adjust the protocols– FixedPriceProduct will not offer a setPrice() method

Page 13: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

13

Adjusting the Protocolsclass Product {

double price, cost;

Product(double p, double c) { price = p; cost = c; }

void getProfit() { return price – cost; }

double getPrice() { return p; }

}

class FixedPriceProduct extends Product {

FixedPriceProduct(double p, double c) { super(p, c); }

}

class NormalProduct extends Product {

NormalProduct(double p, double c) { super(p, c); }

void setPrice(double p) { price = p; }

}

Page 14: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

14

Adjusting the Protocols (cont.)class Store {

Product[] products = ...;

NormalProduct[] normalProducts = ...;

void increaeProfit(double factor) {

for(NormalProduct p : normalProducts) {

double diff = factor * p.getPrice();

p.setPrice(p.getPrice() + diff);

}

}

// Problem: Distinction between NormalProduct and

// FixedPriceProduct has leaked into class Store.

// We lost the benefits of polymorphic messages

Page 15: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

15

</difficulties>

Page 16: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

16

Altering Behavior

• Behavior is defined by bodies of methods• Overriding allows a programmer to change a

method’s body• => Altered behavior can be obtained by means of

overriding

Page 17: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

17

// First example, a Car class

public class Car {

private int speed;

public void setSpeed(int s) {

speed = s;

}

public int getSpeed() { return speed; }

}

public class TalkingCar extends Car {

public void setSpeed(int s) {

super.setSpeed(s);

System.out.println("My new speed is " + s);

}

}

Page 18: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

18

// Second example, a scrabble game

public class Letter {

private char ch;

public Letter(char c) { ch = c; }

public boolean matches(char c) { return ch == c; }

}

public class WildCard extends Letter {

public boolean matches(char c) { return true; }

}

Page 19: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

19

// Third example, scrabble game again

public interface Letter {

boolean matches(char c);

}

public class StandardLetter implements Letter {

private char ch;

public Letter(char c) { ch = c; }

public boolean matches(char c) { return ch == c; }

}

public class WildCard implements Letter {

public boolean matches(char c) { return true; }

}

Page 20: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

20

• Is overriding the only way to alter behavior?

• No!• One can use state to alter behavior

Page 21: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

21

// Varying a car behavior via statepublic class Car { private int speed; private String message;

private Car(String m) { message = m; } public Car() { this(""); }

public void setSpeed(int s) { speed = s; System.out.format(message, s); }

public int getSpeed() { return speed; }

public static Car newTalkingCar() { return new Car("My new speed is %s\n"); }}

Page 22: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

22

// Scrabble: Emulating the wild-card via state

public class Letter {

private char ch;

public Letter(char c) { ch = c; }

public boolean matches(char c) {

return ch == '\0' || ch == c; }

public static newWildCard() {

return new Letter('\0'); }

}

Page 23: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

23

Varying State vs. Overriding

• Is state as powerful as overriding?• Yes!• The general solution: Delegation

Page 24: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

24

Delegation

• The receiver object forwards the incoming message to another object– (Respectively: delegating, delegated)– Delegated performs the “actual” work– Delegating holds the delegated in a field

• New behavior: replace the delegated-to object– Overriding effect via varying state

• Delegated object can offer only a single method– Function Object/Functor/Block/Closure/Command

• A delegating object can hold several delegated-to objects• A delegated object can in turn delegate to another object• Following two slide show the general recipe for replacing

overriding w/ delegation

Page 25: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

25

public class C1 {

public void f() {

// do something

}

}

public class C2 extends C1 {

public void f() {

// do something else

}

}

Page 26: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

26

public interface I { public void f(); }

public class X1 implements I { public void f() { // do something }}

public class X2 implements I { public void f() { // do something else }}

public class C { private I i; public void f() { i.f(); }

private C(I i) { this.i = i; } public static newC1() { return new C(new X1()); } public static newC2() { return new C(new X2()); }}

Page 27: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

27

Delegation in Practice

• Delegating object does some extra work– Wraps the call (synchronize, catch, …)– Caching– Calls a method with a different name– Passes some extra parameters– Computes some other result– …

• Here’s a realistic delegation scenario

Page 28: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

28// No delegation

public class ReportGenerator {

private String[] names;

protected int compareNames(String s1, String s2) {

return s1.trim().compareToIgnoreCase(s2.trim());

}

protected void sort() { ... compareNames(...) ... }

public void printReport(PrintWriter out) {

sort();

for(String name : names)

printName(out, name);

}

protected void printName(PrintWriter out, String name) {

out.println(name);

}

}

Page 29: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

29// With delegation

public class ReportGenerator {

private String[] names;

private Comparator<String> comparator;

private NameFormatter formatter;

public void setFormatter(NameFormatter nf) { ... }

public void setComparator(Comparator<String> c) { ... }

protected void sort() { ... comparator.compare(...) ... }

public void printReport(PrintWriter out) {

sort();

for(String name : names)

printName(out, name);

}

protected void printName(PrintWriter out, String name) {

out.println(formatter.format(name));

}

}

Page 30: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

30

Delegation: Pros

• Modify behavior of an existing object– Change the formatter of a ReportGenerator

• (After it was created!)

• Eliminate combinatorial explosion– 4 name formats– 4 name comparison policies– Total of 16 combinations– Overriding: 16 subclasses – Delegation: 4 formatters, 4 comparators

• Assists in increasing coherency– Dismantling a class into unrelated parts

Page 31: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

31

Creation Point Issues

• Subclassing requires access to creation point– (The class is determined at creation time)

• Creation point may not be accessible– Objects created by a library

• Logic of choosing between subclasses may temper coherency

Page 32: 1 Inheritance & Delegation. 2 Our Starting Point We know OOP Objects are instances of classes Overriding We have used inheritance.

32

Delegation: Cons

• Harder to understand the code– Even the dynamic type does not specify the behavior– => Harder to debug

• In simple cases requires more code

• Difficult to prevent illegal combinations– E.g.: A formatter that requires a specific comparator

• Multiple identities