1

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?

2 Answers 2

2

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.

3
  • Thanks for this, it is helping. What do you mean you do not recomment interfaces at all? I like the interface approach to the controller as it gives a strict definition of what methods are used outside the inner logic. If I change one of the these I have better awareness. Commented Mar 1, 2015 at 18:00
  • Hi Gunnar! You are right, my explanation was a bit lacking. I guess I got lazy towards the end :) Anyway, I added some thoughts to my original answer. Hope it helps ;) Commented Mar 2, 2015 at 20:44
  • I followed your advice. I removed all interfaces from the objects and moved the mutable objects into the controller package, making the setters package-private (default). I then made a new package with all immutable objects for clarity. I kept the interfaces for controller and display, because it enables me to use a different output and is a clear definition of the communication ways. Commented Mar 2, 2015 at 22:55
2

What about designing your "basic objects" as 100% immutable objects?

public final class TodoItem {
    final private String title; 
    final private String content;

    public TodoItem (String title, String content) {
        this.title= title;
        this.content = content;
     }

    public String getTitle() ...
    // no setter at all, title and content can only set when creating a new object
}

Implement your program in terms of such objects, then you can pass them around between arbitrary layers, without the risk of getting unwanted side effects. Here you find a more detailed example.

8
  • This assumes the todo item will never get changed. Unlikely. Commented Feb 28, 2015 at 20:06
  • @GunnarBernstein: instead of changing a "ToDo" item, one has to make a copy with new values and use that object instead of the old one. That's exactly the way the String class in Java is implemented - it has no mutating operations. Do you think it is "unlikely" that a string will never get changed? It is not just "unlikely", it is impossible, but nevertheless you can design any kind of program with immutable objects. The point is: immutability forces you to design your controllers a little bit different.
    – Doc Brown
    Commented Feb 28, 2015 at 21:42
  • The objects are way more complex and contain also objects. If it was so simple like the example object I could easily clone. Suggesting to design all object properties final and then creating a new object anytime anything gets changed is far from being any conceptional help. Read programmers.stackexchange.com/questions/151733/… on the pros and cons of immutable objects. Commented Feb 28, 2015 at 22:24
  • @GunnarBernstein: well, your question was about tiny objects, that was your major concern against option 2). So if you have complex objects you do not want to make immutable, maybe because they have already become legacy code, go with option 2. But you should consider to design small objects as immutable, so you can save the need for additional interfaces. Oh, and from the question you linked to, in the topmost answer: "the most probable cause why people keep creating mutable objects is inertia of mind" - did you consider that this may be exactly your situation?
    – Doc Brown
    Commented Feb 28, 2015 at 22:59
  • If just your politeness would match your knowledge... Commented Mar 1, 2015 at 1:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.