Question

What is the cleanest way in Java to write two versions of the same class where each has a different superclass? By cleanest I mean DRY (least duplicated code). The two classes will have similar but different names and the same code.

The application is Android: class MyActivity extends ActionBarActivity. Class MyActivity34 (for API level 3/4) extends Activity but has the same code as MyActivity. I don't want to keep two copies of everything (in C++ I would use the preprocessor for this). Changing the superclasses is not an option.

Thanks.

Note: The ActionBarActivity class can't be used at API level 3 or 4 (runtime error), so MyActivity34 can't have it anywhere in the inheritance path.

Was it helpful?

Solution 2

Create an interface ,say, MyCommonActivityInterface with all the methods

public interface MyCommonActivityInterface {
    public void sayHello();
    public void sayGoodbye();
}

Create a common activity with all the code

public class MyCommonActivity implements MyCommonActivityInterface {
    ...
    public void sayHello() {Log.d("MyCommonActivity", "says hello")};
    public void sayGoodbye() {Log.d("MyCommonActivity", "says goodbye")};
    ...
}

Now you can reuse the common code in both Activities

public class MyActivity34 extends Activity {
    MyCommonActivityInterface common = new MyCommonActivity();
    public void sayHello() {common.sayHello()};
    public void sayGoodbye() {common.sayGoodbye()};
}

public class MyActivity extends ActionBarActivity {
    MyCommonActivityInterface common = new MyCommonActivity();
    public void sayHello() {common.sayHello()};
    public void sayGoodbye() {common.sayGoodbye()};
}

Well actually the interface can be omitted, but will come handy if you need to swap between alternatives or the like.

I have become really impressed by the powers of Dependency Injection, which can make these kind of things much cleaner.

There is a library called Dagger that adds DI support for android. It has a somewhat steep learning curve but for me it was all worth it.

In this example you would be able to do stuff like:

@Singleton
public class MyCommonActivity  {

    // Example with context to show that it will be automagically injected

    @Inject
    public MyCommonActivity(@ForActivity Context context) {}
    ...
    public void sayHello() {Log.d("MyCommonActivity", "says hello")};
    public void sayGoodbye() {Log.d("MyCommonActivity", "says goodbye")};
    ...
}

public class MyActivity34 extends Activity {

    @Inject MyCommonActivity common;

    public void sayHello() {common.sayHello()};
    public void sayGoodbye() {common.sayGoodbye()};
}

public class MyActivity extends ActionBarActivity {

    @Inject MyCommonActivity common;

    public void sayHello() {common.sayHello()};
    public void sayGoodbye() {common.sayGoodbye()};
}

With a lot of independent classes of code, where some depends on others, or needs a Context object etc,.. simply adding a @Inject line when and where ever you need it saves many lines of code!

And while we are add it, have a look at ButterKnife, much simpler but also only works for injecting Views. Still pretty darn powerful and neat.

OTHER TIPS

I would probably say your best bet is to use composition to encapsulate any duplicate code. Create a class which contains all the shared code and call it from the MyActivity and MyActivity34 classes. Often composition is better/cleaner than strange inheritance structures.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top