Thursday, September 4, 2014

Changing behavior of object at runtime.


annonymous innerclass

Inheritance is a very strong feature in java. Among other things it enables us to change behavior of objects at runtime. Lets consider an example.

Consider a class TextFormat having a method displayText(String msg). The method prints the text message that is passed as param without any formating.


package format;
public class TextFormat {
 public void print(String msg){
  System.out.println(msg);
 }
}

package format;
public class Client {
 public static void main(String[] args) {
  TextFormat tf = new TextFormat();
  tf.print("Testing the power of LATE BINDING");
 }
}
Output : Testing the power of LATE BINDING

A client can call the display method through the interface* TextFormat and see the message displayed on the console.

Note* : Interface in the above para is used as a generic term that defines the operations that a client of an api can perform. And it can mean a class or an interface.

Now the client wants the text to be displayed in a formatted manner say in lower case. But it does not want to change the interface and the method call.
That can be achieved through inheritance and the dynamic/late binding concept.
Note that the only change in the client code is at Line 10. And that can also be moved out of code to the configuration ( generally xml ) using IOC (Inversion of control) pattern. So, effectively the Client code remains untouched and the behavior change is also achieved.


package format;
public class LowerCaseTextFormatter extends TextFormat {
 @Override
 public void print(String msg) {
           System.out.println(msg.toLowerCase());
 }
}

package format;
public class Client {
 public static void main(String[] args) {
    TextFormat tf = new LowerCaseTextFormatter(); // LINE 10
    tf.print("Testing the power of LATE BINDING");
 }
}
Output : testing the power of late binding


Can we achieve such a behavior change without writing a new concrete implementation that extends TextFormat class ?

Consider the below case. We are able to change the behavior of print() method on the fly by creating a anonymous inner class. Although it is a local class and cant be reused outside its scope.


package format;

public class Client {
 
 public static void main(String[] args) {
  /* Changing behaviour of print method 
   * using Anonymous Inner Class
   */
  new TextFormat(){  
   @Override
   public void print(String msg) {
    System.out.println(msg.toLowerCase());
   }
  }.print("Testing the power of LATE BINDING");
 }
}
Output : testing the power of late binding

The compiler version of anonymous inner class does extend the TextFormat class.


1 comment: