Search code examples
javaoopconventions

Where should I store lists or maps of objects


In my project I have several objects like layouts, groups, boxes and many others. These objects need to be stored in a list or map with methods to get, remove and put them into the collection. I am currently using static methods and variables in the associated class, for example I have:

public class Layout {
    private static Map<String, Layout> layouts = new HashMap<String, Layout>();
    /*
    Other, non-static variables
     */

    public static void addLayout(String name, Layout layout) {
        layouts.put(name, layout);
    }

    public static Layout getLayout(String name) {
        return layouts.get(name);
    }

    public static void removeLayout(String name) {
        layouts.remove(name);
    }

    /*
    Non-static methods for layout
     */
}

Would it be better to have a separate class that holds the collection of each kind of object or a single class to hold collections of all the objects? If so, what kinds of names would you use for these classes?


Solution

  • The good point of your solution is that you have all belonging to Layout in one class, no more dependencies needed. But using static methods will make it hard to test implementations using that static methods. I won't use one class to hold all, that would create a dependency magnet.

    A better approach may be to create repositories for each of the classes like LayoutRepository for storing and retrieving Layouts. Best to use with dependency injection implemented by a container like Spring if your application becomes bigger.

    The most simple would be a generic implementation:

    public class Repository<E> {
    
      private final ConcurrentMap<String,E> elements = new ConcurrentHashMap<>();
    
      public void add(String name, E element) {
        elements.put(name, element);
      }
    
      public E get(String name) {
        return elements.get(name);
      }
    
      public void remove(String name) {
        elements.remove(name);
      }
    }
    

    So you have the implementation of the repository separated from the class to store. You can simply reimplement the functionality using a file or database without touching the code using it.

    For unit tests you can simply mock the repository to make sure it is used right.

    If the creation of the class e.g. Layout have to ensure a valid state, a builder would be a good improvement. Another option is to use a factory to have control over creation of instances. Both should be placed in the same package as the element class and the constructor than must no longer be public.