Homegrown Java mixins

2008-12-16 by mira

Lets be nostalgic and think about the cell phone capabilities five years ago. Cell phones were basically phones, not much more. Cameras were cameras and music players could play music.

public interface Phone {
  void call();
}

public interface Camera {
  void takePicture();
}

public interface MusicPlayer {
  void playMusic();
}

Now how about combining the capabilities of phone, camera and music player into one device? - Let’s call it MyPhone!

interface MyPhone extends Phone, Camera, MusicPlayer {
}

In Java, composition of functionality is commonly achieved with delegation in so called forwarding classes. An implementation looks like this.

static class MyPhoneImpl implements MyPhone {

  private final Phone phone;
  private final Camera camera;
  private final MusicPlayer player;

  MyPhoneImpl(Phone phone, Camera camera, MusicPlayer player) {
    this.phone = phone;
    this.camera = camera;
    this.player = player;
  }

  @Override
  public void call() {
    phone.call();
  }

  public void takePicture() {
    camera.takePicture();
  };

  @Override
  public void playMusic() {
    player.playMusic();
  }
}

No black magic here, but implementing all those forwarding methods is tedious. Moreover we have a very basic phone here, still laking capabilities like messaging, address book, recording movies, etc.

Other programming languages have support for mixins or traits. They are very useful for componentized software development because they encourage code reuse without the burden of multiple inheritance.

Unfortunately, Java doesn’t support mixins (yet?). But Java has its Proxy facility to accomplish interface implementation and delegation dynamically (some more info here). With this Proxy, we are able to build our own mixin solution.

Exactly where are we heading? Well, we want a simple solution for our MyPhone implementation that relieves us from the burden of writing the MyPhoneImpl class ourselves, something like this:

final Phone phone = new PhoneImpl();
final Camera camera = new CameraImpl();
final MusicPlayer player = new MusicPlayerImpl();

final MyPhone myPhone = ObjectBlender.createProxy(MyPhone.class, phone, camera, player);

ObjectBlender takes care of implementing the MyPhone interface by auto-wiring the forwarding methods to the matching delegates and creating the necessary proxy instance dynamically using Javas Proxy facility. Voilà!

Source code is here.

Archive

architecture