Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ways to achieve effective Java traits?

Please let me know if this is inappropriate as formulated (in particular whether Programmers.SE or something would be better for the question.)

Alright. So I've got a number of 'traits' that I'm currently expressing as interfaces. Let's call them "updatable" and "destructible". Expressing them as interfaces has the downside that I can't share behavior between all "destructible" components; on the other hand, expressing these as abstract classes mean I can't mix and match without explicitly defining the mixed trait as another abstract class ("UpdateableAndDestructible") and furthermore this feels like an abuse of the abstract class functionality at that point. It's probably what I'll end up doing if there aren't cleaner ways of handling this, however.

What are my options as far as pure Java solutions to this conundrum? Is it possible for me to describe shared behavior and then mix and match as I see fit without having to explicitly describe every permutation I'll be using?

like image 951
Joseph Weissman Avatar asked Aug 22 '11 18:08

Joseph Weissman


3 Answers

Maybe you could achieve the goal by using a mix of interfaces and default implementations.

Like:

public interface Updatable {
  void updated();
}

public interface Loadable {
  void load();
}

public class DefaultUpdatable implements Updatable {
 ...
}

public class DefaultLoadable implements Loadable {
 ...
}

public class SomeObject implements Updatable, Loadable {
  private final Updatable updatable = new DefaultUpdatable();
  private final Loadable loadable = new DefaultLoadable();

  public void load() {
    this.loadable.load();
  }

  public void updated() {
    this.updatable.updated();
  }
}

Still noisy and maybe not as flexible as you would like but maybe a bit cleaner than doing the UpdatableAndDestructable thing.

like image 153
Rickard Avatar answered Sep 28 '22 17:09

Rickard


I don't think there is a pretty solution to this problem, but maybe a few workable ones depending on how much you despise the boilerplate.

You could define a trait as another class + interface, that takes the instance object as the first parameter. And them implement the interface with the class you want to have the trait. Then create stub methods that call the methods on the trait impl.

public class MyClass implements MyTrait {
    @Override
    public void doSomething() {
        MyTraitImpl.doSomething(this);
    }
}

And then for the trait itself:

public interface MyTrait {
    public void doSomething();
}

public class MyTraitImpl {
    public static void doSomething(MyTrait obj) {
        // do something with obj
    }
}

As Ernest Friedman-Hill says tho, Scala does this for you (as I understand it, this is how it implements traits on the JVM).

like image 44
Jason Wheeler Avatar answered Sep 28 '22 19:09

Jason Wheeler


I know you said "pure Java", but this is something Scala does well. Limitations in the Java language itself are a strong driver for people to adopt other JVM languages...

like image 41
Ernest Friedman-Hill Avatar answered Sep 28 '22 19:09

Ernest Friedman-Hill