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