1 inheritance & delegation. 2 our starting point we know oop objects are instances of classes...

32
1 Inheritance & Delegation

Post on 20-Dec-2015

219 views

Category:

Documents


0 download

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