Showing posts with label object. Show all posts
Showing posts with label object. Show all posts

Tuesday, 10 September 2013

Making Java’s Multiple Interface Inheritance more “adaptable”

If there's one feature that I like about Multiple Inheritance, that would be "adaptability". When a child is inherited from multiple parent, child will automatically "adapts" to all the changes made in all the parents, from then and onwards. No explicit changes in child is required, in order to keep it "compatible" or "in-sync" with the parents.

How is it different in Java? in Java, the concept of Multiple Inheritance is further split up into Multiple Interface Inheritance and Multiple Implementation Inheritance specifically. Java supports the former and relinquish the later.

Consider a typical example of TypeC inheriting from TypeA and TypeB. In Java, the closest you can come to Multiple Implementation Inheritance (functionally) is as follows:

public interface TypeA { 
void methodA();
}
public interface TypeB { 
void methodB();
}
//multiple interface inheritance
public interface TypeC extends TypeA, TypeB {
void methodA();
}

public class TypeAImpl implements TypeA {

@override
public void methodA() {
System.out.println("method A");
}
}

public class TypeBImpl implements TypeB {
@override
public void methodB() {
System.out.println("method B");
}
}

public class TypeCImpl implements TypeC (

//object composition
private TypeAImpl delegateAImpl;
private TypeBImpl delegateBImpl;

@override
public void methodA() {
//method delegation
delegateAImpl.methodA();
}
@override
public void methodB() {


//method delegation
delegateBImpl.methodB();
}
@override
public void methodC() {
System.out.println("method C");
}
}

 


Problem? lack of "adaptability"


In our example above, we try to emulate Multiple Implementation Inheritance as closely as possible using:


  • Multiple Interface Inheritance
  • Object Composition
  • Method Delegation

However, contrary to the Multiple Implementation Inheritance, the child still, will not "adapts" to any of the following changes made to the parents. Even worst, these changes will break the child:


  • Add a new method - if we declare a new methodA2 in TypeA and define its implementation in TypeAImpl. TypeC will instantly adapts to the change in TypeA due to multiple interface inheritance. And, because TypeCImpl implements TypeC, it will also adapts to the newly declared methodA2 in TypeA. And so, TypeCImpl will break instantly because it either needs (a). the implementation of methodA2 to be defined OR (b). to change its type from a concrete class to an abstract class.
  • Update the signature of an existing method - if we change signature of methodB in TypeB from "void methodB()" to "void methodB(int b)" and similarly change its implementation in TypeBImpl. TypeC will instantly adapts to the change in TypeB due to multiple interface inheritance. And, because TypeCImpl implements TypeC, it will also adapts to the recently changed methodB in TypeB. And so, TypeCImpl will break instantly because it either needs (a). the implementation of "void methodB(int b)" to be defined OR (b). to change its type from a concrete class to an abstract class. Also, note that the methodB implementation in TypeCImpl will now start complaining about the erroneous code "delegateBImpl.methodB()" because such a method does not exists in TypeBImpl any more.
  • Remove an existing method - if we remove methodB declaration in TypeB and implementation in TypeBImpl. TypeC will instantly adapts to the change in TypeB due to multiple interface inheritance. And, because TypeCImpl implements TypeC, it will also adapts to the recent removal of methodB in TypeB and TypeBImpl. And so, TypeCImpl will break instantly because the methodB implementation in TypeCImpl will now start complaining about the erroneous code "delegateBImpl.methodB()" because such a method does not exists in TypeBImpl any more.

All of the changes above require mandatory changes in child as well and this sucks big time! any change to any one of the parent components, will "force" a ripple effect of mandatory changes to all of the child components down the hierarchy and if you don't do that, it'll break them apart.

Let me raise the bar a little more, assume if, TypeA and TypeB belongs to publicly published APIs, ApiTypeA-1.0.jar and ApiTypeB-1.0.jar. And then one or more of the changes mentioned above is made to those APIs in their next releases, ApiTypeA-2.0.jar and ApiTypeB-2.0.jar respectively. Now, if you don't want the changes, that's fine, you can keep pointing to the older version 1.0 of the dependencies and there won't be any issues. But, most likely in a real world scenario, at some point you need the upgrade to newer versions of the dependencies. But, you can not do that, until and unless you have the necessary resources to make appropriate changes in your code otherwise it will break your code.

Think of those cases specifically, where only additions are being made to relatively newer component(s) in order to add more functionality to make them feature rich. Additional methods/features, with out any changes or removals to existing ones, should not have any impact, the transition should be seamless, but this is not the case as shown above.

So, to make Multiple Interface Inheritance more "adaptable" and to bring it (functionally) one step closer to Multiple Implementation Inheritance with out the negatives of the later, becomes the motivation of Project MI+.

Friday, 6 September 2013

Project MI+ | Multiple Inheritance in Java like never before!

 

project mi  logo

Project MI+ add multiple inheritance support to your java classes, so they can (functionally) "extend" (read inherit) from multiple parent classes.

Project MI+ is an open source project published under Apache Public License version 2.0.

Suppose we want to inherit our Child class from two parent classes: (1) ParentOne and (2) ParentTwo.

public class ParentOne {
public void parentOneMethod() {
System.out.println("parent one method");
}
}

public class ParentTwo {
public void parentTwoMethod() {
System.out.println("parent two method");
}
}

First we will 'extract' interfaces from the parent classes mentioned above. [Project MI+ promotes the use of classic design principle 'Program to Interface']

public interface ParentOne {
void parentOneMethod();
}

public interface ParentTwo {
public void parentTwoMethod();
}

public class ParentOneImpl implements ParentOne {
public void parentOneMethod() {
System.out.println("parent one method");
}
}

public class ParentTwoImpl implements ParentTwo {
public void parentTwoMethod() {
System.out.println("parent two method");
}
}

Now we can simply:


  1. Create a Child interface,
  2. Extend it from parent interfaces,
  3. Add "Multiple Inheritance Support" by annotating the Child interface with MISupport (JavaDoc | Source Code) annotation.
import com.smhumayun.mi_plus.MISupport;

@MISupport(parentClasses = {ParentOneImpl.class, ParentTwoImpl.class})
public interface Child extends ParentOne, ParentTwo {
}

For multiple inheritance to work, you should always create new instances of MISupport (JavaDoc | Source Code) annotated classes (only) via MIFactory (JavaDoc | Source Code) instead of directly instantiating them using java's new keyword and a constructor.

import com.smhumayun.mi_plus.MIFactory;

...
MIFactory miFactory = new MIFactory();
Child child = miFactory.newInstance(Child.class);
child.parentOneMethod();
child.parentTwoMethod();
...

The child now refers to an object which (functionally) inherits methods from all the parent classes.

Click here to read more about Project MI+

Friday, 12 July 2013

XStream - One of the best Java and XML Framework around

xstreamXStream is for sure one of the best Java and XML frameworks around. It offers great ease of use, simplistic approach and fun to work with.

From the authors “XStream is a simple library to serialize objects to XML and back again.”

Let me show you how simple it is:

String xml = xstream.toXML(domainObject);

That’s it! Smile

Consider a simple domain object class:

In order to convert or serialize that domain object to xml, all you have to do is following:

The output of the above program is:

What if, you want to convert or deserialize the xml back to java object?

DomainObject domainObject = (DomainObject) xstream.fromXML(xml);

Some of the cool features of XStream includes:

  • Ease of use. A high level facade is supplied that simplifies common use cases.
  • No mappings required. Most objects can be serialized without need for specifying mappings.
  • Performance. Speed and low memory footprint are a crucial part of the design, making it suitable for large object graphs or systems with high message throughput.
  • Clean XML. No information is duplicated that can be obtained via reflection. This results in XML that is easier to read for humans and more compact than native Java serialization.
  • Requires no modifications to objects. Serializes internal fields, including private and final. Supports non-public and inner classes. Classes are not required to have default constructor.
  • Full object graph support. Duplicate references encountered in the object-model will be maintained. Supports circular references.
  • Integrates with other XML APIs. By implementing an interface, XStream can serialize directly to/from any tree structure (not just XML).
  • Customizable conversion strategies. Strategies can be registered allowing customization of how particular types are represented as XML.
  • Error messages. When an exception occurs due to malformed XML, detailed diagnostics are provided to help isolate and fix the problem.
  • Alternative output format. The modular design allows other output formats. XStream ships currently with JSON support and morphing.