Java MVC – How to Handle Basic Objects with Interfaces

javaobject-oriented-design

I have an (android) application and decided that the presentation layer will get data only through strict interfaces from the controller. I am at the point where some basic objects need to be passed to the presentation layer, but the objects itself must be in strict read-only mode, because all changes will be handled by the controller.

To make a simple example, imagine a ToDo-App, where the screen needs to display a list of todo items.

The Todo-Item has the fields "title" and "content" with respective getters and setters. Even if I pass an unmodifiable list, the objects in it can be changed. I can think of these alternatives:

  1. put controller and data in one package and make the setters protected.
  2. add an interface to the todo item containing only the getters and passing these objects.
  3. add an interface only to the controller and put all getters there.

for 1)

public class TodoItem {
    private String title; private String content;
    public String getTitle() ...
    protected String setTitle(..) ...
}

for 2)

public interface ITodoItem {
    public String getTitle();
}

public class TodoItem implements ITodoItem {
    private String title; private String content;

    @Override
    public String getTitle() ...

    public String setTitle(..) ...
}

I wonder now what is the more common, smarter etc. option (or are there more?) and what are the arguments?

Alternative 1) for my feeling depends to much on the fact, that the items have to be in the same package making it to difficult to expand the program.

Alternative 2) looks odd to me, because all tiny objects would now become an interface with the getter methods. I am using it and technically I am satisfied (as it prevents me from accidantally changing an object). However, it is not immutable, as the object may be cast back to ToDo-Item and then the original is changed. So this is not good for public apis. Do I really have to clone every object if I want immutability?

Alternative 3) gets messy quick because one controller would then contain all the getters of the tiny objects. This does not comply to "let the object do the work".

What are your experiences and thoughts on this?

Best Answer

Having over-engineered one or two systems in my career, I will try to answer this from a pragmatic point of view.

My first approach would be to establish the convention, that data must not be modified in the presentation layer. If you work alone you know your own conventions anyway. In a small team you should be able to communicate them easily. Yes, this does not prevent violations at compile time, but unintentional violations should be rare and easy to spot (call hierarchy of a certain setter, for example).

If you absolutely need/want to implement this rule in code, putting the controllers and their respective data objects into a single package each, is the next best thing. Also I would not use protected, but default/package scope (i.e. omit the visibility keyword). Of the three options you presented, this is the most light weight (and therefore best maintainable and scalable) approach. You shouldn't be too worried about "...making it to difficult to expand the program.", you mereley have to live with potentially a lot of classes in one package. Maybe you can mitigate this by cleverly grouping certain controllers with some objects into their own package.

If this approach also fails, immutable objects are what you want. You could implement them plain (constructor and copy constructor, no setters), with factories/factory methods, or even use the Builder Pattern. Just keep in mind, that the overhead (i.e. boiler plate code) increases significantly with this solution and you should ask yourself if the gain (less time spent hunting/fixing bugs) is really greater than the cost (writing, testing and maintaining boiler plate code). In fact I would only recommend this solution if you can guarantee, that the objects never need to be modified, and therefore you can ditch the copy code. This does not seem to be the case for your example, though.

Introducing a special getter-interface for each(!) data-class means more overhead than protected/default setters and is only half as strict, as you mentioned yourself: One could always downcast to the actual data-class. To improve this, you could give your data-classes protected or package visibility and put them in the same package as the controllers, but then you are back at square one, with additional interfaces and complexity.

Keeping the controllers and the data-model separated is a good idea. For most applications the model is much more likely to change than the controller logic. And you want to keep that changing part contained, since every change potentially introduces a bug and means additional adaptations in the test- and client code. By moving and/or wrapping the getters directly into the controller (with or without special interfaces) you also increase the scope of the change. You'd suddenly need to maintain the test- and client code of the controller, instead of just the model, if you want to add/change one field. Another, simpler problem is, if you need a collection of non-primitive data in your model.

Any software design decision boils down to the question of which solution lets you, your colleagues and users work most efficiently. These three groups will likely have contradictory needs and so it is hard to find the absolutely best solution and trade-offs are almost always a part of it.

Related Topic