Designing with inheritance

Bruce Eckel's Thinking in Java Contents | Prev | Next

//: Transmogrify.java
// Dynamically changing the behavior of
// an object via composition.
 
interface Actor {
  void act();
}
 
class HappyActor implements Actor {
  public void act() { 
    System.out.println("HappyActor"); 
  }
}
 
class SadActor implements Actor {
  public void act() { 
    System.out.println("SadActor");
  }
}
 
class Stage {
  Actor a = new HappyActor();
  void change() { a = new SadActor(); }
  void go() { a.act(); }
}
 
public class Transmogrify {
  public static void main(String[] args) {
    Stage s = new Stage();
    s.go(); // Prints "HappyActor"
    s.change();
    s.go(); // Prints "SadActor"
  }
} ///:~ 

A Stage object contains a handle to an Actor, which is initialized to a HappyActor object. This means go( ) produces a particular behavior. But since a handle can be re-bound to a different object at run time, a handle for a SadActor object can be substituted in a and then the behavior produced by go( ) changes. Thus you gain dynamic flexibility at run time. In contrast, you can’t decide to inherit differently at run time; that must be completely determined at compile time.

Pure inheritance vs. extension

Downcasting and run-time

type identification

//: RTTI.java
// Downcasting & Run-Time Type
// Identification (RTTI)
import java.util.*;
 
class Useful {
  public void f() {}
  public void g() {}
}
 
class MoreUseful extends Useful {
  public void f() {}
  public void g() {}
  public void u() {}
  public void v() {}
  public void w() {}
}
 
public class RTTI {
  public static void main(String[] args) {
    Useful[] x = {
      new Useful(),
      new MoreUseful()
    };
    x[0].f();
    x[1].g();
    // Compile-time: method not found in Useful:
    //! x[1].u();
    ((MoreUseful)x[1]).u(); // Downcast/RTTI
    ((MoreUseful)x[0]).u(); // Exception thrown
  }
} ///:~ 

As in the diagram, MoreUseful extends the interface of Useful. But since it’s inherited, it can also be upcast to a Useful. You can see this happening in the initialization of the array x in main( ). Since both objects in the array are of class Useful, you can send the f( ) and g( ) methods to both, and if you try to call u( ) (which exists only in MoreUseful) you’ll get a compile-time error message.

If you want to access the extended interface of a MoreUseful object, you can try to downcast. If it’s the correct type, it will be successful. Otherwise, you’ll get a ClassCastException. You don’t need to write any special code for this exception, since it indicates a programmer error that could happen anywhere in a program.



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

  • Savvy enterprises are discovering that the cloud holds the power to transform IT processes and support business objectives. IT departments can use the cloud to redefine the continuum of development and operations—a process that is becoming known as DevOps. Download the Executive Brief DevOps: Why IT Operations Managers Should Care About the Cloud—prepared by Frost & Sullivan and sponsored by IBM—to learn how IBM SmartCloud Application services provide a robust platform that streamlines …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds