16

I have a conceptual problem with a proper implementation of code which seems require multiple inheritance, that would not be a problem in many OO languages, but as the project is for Android, there is no such thing like multiple extends.

I have a bunch of activities, derived from different base classes, such as simple Activity, TabActivity, ListActivity, ExpandableListActivity, etc. Also I have some code fragments which I need to place into onStart, onStop, onSaveInstanceState, onRestoreInstanceState and other standard event handlers in all activities.

If I have a single base class for all activities, I'd place the code into a special intermediate derived class, and then create all activities extending it. Unfortunately, this is not the case, because there are multiple base classes. But placing the same portions of code into several intermediate classes is not a way to go, imho.

Another approach could be to create a helper object and delegate all calls of the abovementioned events to the helper. But this requires the helper object to be included, and all handlers to be redefined in all intermediate classes. So there is no much difference to the first approach here - still a lot of code duplicates.

If a similar situation occured under Windows, I'd subclass base class (something that "corresponds" to the Activity class in Android) and trap appropriate messages there (in a single place).

What can be done in Java/Android for this? I know there is interesting tools such as Java instrumentation (with some real examples), but I'm not a Java guru, and not sure if it's worth trying in this specific case.

If I missed some other decent solutions, please, mention them.

UPDATE:

For those who may be interested in solving the same problem in Android I've found a simple workaround. There exist the Application class, which provides, among other things, the interface ActivityLifecycleCallbacks. It does exactly what I need allowing us to intercept and add some value into important events for all activities. The only drawback of this method is that it's available starting from API level 14, which is not enough in many cases (support for API level 10 is a typical requirement today).

    5 Answers 5

    6

    I am afraid you can-t implement your classsystem without codeduplication in android/java.

    However you can minimize codeduplication if you combine special intermediate derived class with composite helper object. This is called the Decorator_pattern:

     class ActivityHelper { Activity owner; public ActivityHelper(Activity owner){/*...*/} onStart(/*...*/){/*...*/} } public class MyTabActivityBase extends TabActivity { private ActivityHelper helper; public MyTabActivityBase(/*...*/) { this.helper = new ActivityHelper(this); } protected void onStart() { super.onStart(); this.helper.onStart(); } // the same for onStop, onSaveInstanceState, onRestoreInstanceState,... } Public class MySpecialTabActivity extends MyTabActivityBase { // non helper logic goes here .... } 

    so every base class you create an intermediate baseclass that delegates its calls to the helper. The intermediate basesclasses are identical except the the baseclase where they inherit from.

    1
    • 1
      Yes, thank you. I know the decordator pattern. This is a last resort, which though actually demonstrates what I'd prefer to avoid - code duplication. I'll accept your answer, if no other instersting ideas apper. Can I possibly use generics to generalize the code of the "intermediates"?
      – Stan
      CommentedDec 23, 2012 at 15:56
    6

    I think you're trying to avoid the wrong type of code duplication. I believe Michael Feathers wrote an article about this but unfortunately I can't find it. The way he describes it is you can think of your code as having two parts like an orange: The rind and the pulp. The rind is the stuff like method declarations, field declarations, class declarations, etc. The pulp is the stuff inside these methods; the implementation.

    When it comes to DRY, you want to avoid duplicating pulp. But often in the process you create more rind. And that's ok.

    Here's an example:

    public void method() { //rind boolean foundSword = false; for (Item item : items) if (item instanceof Sword) foundSword = true; boolean foundShield = false; for (Item item : items) if (item instanceof Shield) founShield = true; if (foundSword && foundShield) //... } //rind 

    This can be refactored into this:

    public void method() { //rind if (foundSword(items) && foundShield(items)) //... } //rind public boolean foundSword(items) { //rind return containsItemType(items, Sword.class); } //rind public boolean foundShield(items) { //rind return containsItemType(items, Shield.class); } //rind public boolean containsItemType(items, Class<Item> itemClass) { //rind for (Item item : items) if (item.getClass() == itemClass) return true; return false; } //rind 

    We added a lot of rind in this refactoring. But, the second example has a much cleaner method() with less DRY violations.

    You said you'd like to avoid the decorator pattern because it leads to code duplication. If you look at the image in that link you'll see it will only duplicate the operation() signature (ie: rind). The operation() implementation (pulp) should be different for each class. I think your code will end up cleaner as a result and have less pulp duplication.

      3

      You should prefer composition over inheritance. A nice example is the IExtension "pattern" in the .NET WCF framework. Baiscally you have 3 interfaces, IExtension, IExtensibleObject and IExtensionCollection. You can then compose the different behaviors with an IExtensibleObject object by addig IExtension instances to it's Extension IExtensionCollection property. In java it should look something like that, not however that you have to create your own IExtensioncollection implementation that calls the attach and detach methods when items are being added/removed. Also note that it is up to you to define the extension points in your extensible class The example uses an event-like callback mechanism:

      import java.util.*; interface IExtensionCollection<T> extends List<IExtension<T>> { public T getOwner(); } interface IExtensibleObject<T> { IExtensionCollection<T> getExtensions(); } interface IExtension<T> { void attach(T target); void detach(T target); } class ExtensionCollection<T> extends LinkedList<IExtension<T>> implements IExtensionCollection<T> { private T owner; public ExtensionCollection(T owner) { this.owner = owner; } public T getOwner() { return owner; } public boolean add(IExtension<T> e) { boolean result = super.add(e); if(result) e.attach(owner); return result; } // TODO override remove handler } interface ProcessorCallback { void processing(byte[] data); void processed(byte[] data); } class Processor implements IExtensibleObject<Processor> { private ExtensionCollection<Processor> extensions; private Vector<ProcessorCallback> processorCallbacks; public Processor() { extensions = new ExtensionCollection<Processor>(this); processorCallbacks = new Vector<ProcessorCallback>(); } public IExtensionCollection<Processor> getExtensions() { return extensions; } public void addHandler(ProcessorCallback cb) { processorCallbacks.add(cb); } public void removeHandler(ProcessorCallback cb) { processorCallbacks.remove(cb); } public void process(byte[] data) { onProcessing(data); // do the actual processing; onProcessed(data); } protected void onProcessing(byte[] data) { for(ProcessorCallback cb : processorCallbacks) cb.processing(data); } protected void onProcessed(byte[] data) { for(ProcessorCallback cb : processorCallbacks) cb.processed(data); } } class ConsoleProcessor implements IExtension<Processor> { public ProcessorCallback console = new ProcessorCallback() { public void processing(byte[] data) { } public void processed(byte[] data) { System.out.println("processed " + data.length + " bytes..."); } }; public void attach(Processor target) { target.addHandler(console); } public void detach(Processor target) { target.removeHandler(console); } } class Main { public static void main(String[] args) { Processor processor = new Processor(); IExtension<Processor> console = new ConsoleProcessor(); processor.getExtensions().add(console); processor.process(new byte[8]); } } 

      This approach has the benefit of extension reuse if you manage to extract common extension points between your classes.

      4
      • 1
        Maybe it's because I don't use .NET, but I found this answer very hard to understand. Can you add an example of using these three interfaces?CommentedDec 23, 2012 at 19:41
      • Thank you, very interesting. But wouldn't it be much simplier just to register extension's callbacks in extensible object? Something like processor.addHandler(console) provided that ConsoleProcessor would implement callback interface itself. The "extension" pattern looks like a mixin of visitor and decorator, but is it necessary in this case?
        – Stan
        CommentedDec 24, 2012 at 9:44
      • If you register extensions directly in the Processor (== ExtensibleObject) you have tight cupling. The idea here is to have extensions that can be reused between extensible objects with the same extension points. In fact the pattern is mora like a mixin pattern simulation.
        – m0sa
        CommentedDec 24, 2012 at 13:05
      • Hm, I'm not sure a binding by interface is a tight coupling. Most interesting thing is that even by the extension pattern both extensible object and extension relies on the same worker interface ("callback"), so the coupling remains the same, imho. In other words, I can not plug existing extension into a new extensible object without a coding for support of the worker interface in the "processor". If the "extension point" means actually the worker interface, then I don't see a difference.
        – Stan
        CommentedDec 25, 2012 at 17:34
      0

      Starting in Android 3.0, it may be possible to solve this elegantly by using a Fragment. Fragments have their own lifecycle callbacks and can be placed inside an Activity. I'm not sure this will work for all the events though.

      Another option I'm also not sure about (lacking in-depth Android know-how) might be to use a Decorator in the opposite way k3b suggests: create an ActivityWrapper whose callback methods contain your common code and then forward to a wrapped Activity object (your actual implementation classes), and then have Android start that wrapper.

        -3

        It is true that Java doesn't allow multiple-inheritance, but you could simulate it more or less by making each one of your SomeActivity subclasses extend the original Activity class.

        You'll have something like:

        public class TabActivity extends Activity { . . . } 
        1
        • 2
          This is what the classes already do, but the Activity base class is part of the Android API and cannot be changed by developers.CommentedDec 23, 2012 at 16:36

        Start asking to get answers

        Find the answer to your question by asking.

        Ask question

        Explore related questions

        See similar questions with these tags.