1 / 32

Inheritance & Delegation

Inheritance & Delegation. Our Starting Point. We know OOP Objects are instances of classes Overriding We have used inheritance. Terminology. Per class Forge: Signatures of accessible constructors Mill: Bodies of constructor Protocol: Signatures of accessible fields, methods

aden
Download Presentation

Inheritance & Delegation

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. 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

  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>

  5. public 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

  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 messages for(Product x : products) { double price = x.discountPrice(0.7); .. } • Implementing classes: Product, FixedPriceProduct

  7. class 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; } }

  8. <difficulties>

  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(); } }

  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! }

  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 !!

  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

  13. Adjusting the Protocols class 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; } }

  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

  15. </difficulties>

  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

  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); } }

  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; } }

  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; } }

  20. Is overriding the only way to alter behavior? • No! • One can use state to alter behavior

  21. // Varying a car behavior via state public 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"); } }

  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'); } }

  23. Varying State vs. Overriding • Is state as powerful as overriding? • Yes! • The general solution: Delegation

  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

  25. public class C1 { public void f() { // do something } } public class C2 extends C1 { public void f() { // do something else } }

  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()); } }

  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

  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); } }

  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)); } }

  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

  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

  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

More Related