Search code examples
androidiosflutterclassoop

What's the best way to properly manage a model classes?


When I build mobile apps (but platform doesn't matter) I run into trouble with model classes.

For example, let's say I will have model class called User with properties id, name and age. I fetch users from remote API, parse JSON into instance of this model class and these properties are being displayed somewhere in list (note that other properties are not present in JSON response). So far, so good.

But at some point, in another part of the application I will also need to obtain other User's properties, such as address, email, etc. I'm having a hard time deciding how to proceed and that's also my question. Should I now create a new model class? Inherit from User class? Or make all fields nullable?

Basically what I do everytime is that I set every properties as nullable and populate only what is needed. Is this good approach? I can't shake the feeling that there is a better way to do it.


Solution

  • First, we need to define the interfaces. The interface segregation principle tells us:

    No code should be forced to depend on methods it does not use.

    It follows that we should not have in the interface for the client, which uses only the name(), age() methods, the other methods are: email(), address(). Also, you shouldn't use null (there are many articles explaining why null is evil).

    Second, if you have properties in a class and you just make getters for them, then you will get a class with low cohesion, which is also not good.

    Cohesion refers to the degree to which the elements inside a module belong together. In one sense, it is a measure of the strength of relationship between the methods and data of a class and some unifying purpose or concept served by that class. In another sense, it is a measure of the strength of relationship between the class's methods and data.

    Let's try to put these ideas together now.

    interface User {
        String name();
        int age();
    }
    
    interface DetailedUser extends User {
        String email();
        String address();
    }
    
    final class JsonUser implements User {
    
        private Json json;
    
        public JsonUser(Json json) {
            this.json = json;
        }
    
        @Override
        public String name() {
            // getting from json the name of the user
        }
    
        @Override
        public int age() {
            // getting from json the age of the user
        }
    }
    
    final class JsonDetailedUser implements DetailedUser {
    
        private User user;
        private Json json;
    
        public JsonDetailedUser(User user, Json json) {
            this.user = user;
            this.json = json;
        }
    
        @Override
        public String name() {
            return user.name();
        }
    
        @Override
        public int age() {
            return user.age();
        }
    
        @Override
        public String email() {
            // getting from json the email of the user
        }
    
        @Override
        public String address() {
            // getting from json the address of the user
        }
    }
    

    P.S. I know this is a different approach than you are using (your models are essentially data structures, I suggest making them objects with real behavior - let them parse a piece of JSON and pull out details about the user). I hope this is what you were looking for and it will help you.