1
public class Person
{
    protected Map<String, String> data;

    public String getString(String key)
    {
        return getData().get(key);
    }

    public void setString(String key, String val)
    {
        getData().put(key, val);
    }
}

I want a flexible object that could change and have new fields eventually, or fields eventually go unused based on a users needs.

Say at first the user just needs the basic fields: Name, Age, Height.

But later on another user needs to capture: Hair Color, Eye Color, & Ethnicity, on top of the already used fields

Would using a String, String map be viable?

I could create all the fields

int age;
int height;
String name;
String eyeColor;
...

But my "Person" could only extend so far with just these fields. Not sure what the best practice is for this, or if the string map is the route go. Any insight would be appreciated.

Well the project is a crud application that is used for insurance purposes. Each branch company stores drivers differently and uses driver information differently, as what data fields are captured and what are not. Some capture how many accidents someone has been in, some do not. Some require years driving, and a driver grade, while some do not. I wasn't sure the best design practice to make a flexible object, that extends to the cases of each branch company, without creating multiple driver extended objects, because everytime a new carrier comes in, i need a new object for their needs

Using:

Java JSP/Struts2 MySQL as DB.

rghome
  • 8,529
  • 8
  • 43
  • 62
ThePirateBae
  • 89
  • 12
  • If you know your keys are always going to be Strings (i.e., "Name," "Height," "Age," etc) you could perhaps do . It would make it a big more generic, and you can always parse objects in different ways. Is there more context to this problem? We could probably give you more insight if we know what the Person was for and how/when fields would be added within the program. – Sarah Oct 06 '17 at 18:20
  • 2
    If you're opposed to strong types, are you sure you want to use Java? It might be easier to switch languages than to circumvent basic language design. – azurefrog Oct 06 '17 at 18:20
  • 2
    It is dynamic, but quit peformance heavy compared to plain fields. I would make sure you cannot use a base class which other users can extend, or the decorator pattern for example before falling back to your proposed solution. – n247s Oct 06 '17 at 18:20
  • You are going to need to be more specific then that, it can sometimes be okay. What design problem are you actually trying to solve? – Oleg Oct 06 '17 at 18:21
  • @Oleg Well the project is a crud application that is used for insurance purposes. Each branch company stores drivers differently and uses driver information differently, as what data fields are captured and what are not. Some capture how many accidents someone has been in, some do not. Some require years driving, and a driver grade, while some do not. I wasn't sure the best design practice to make a flexible object, that extends to the cases of each branch company, without creating multiple driver extended objects, because everytime a new carrier comes in, i need a new object for their needs – ThePirateBae Oct 06 '17 at 18:24
  • @n247s yes performance heavy is what i was scared of, that was my biggest drawback. Thanks for the direction of looking into the decorator pattern, or using extended classes (my second thought to this one). – ThePirateBae Oct 06 '17 at 18:25
  • @azurefrog i came aboard this project that uses Java and JSP's, with a MySQL db. Cant switch now :(... So limited to what i can do .. – ThePirateBae Oct 06 '17 at 18:27
  • Libraries like Jackson can help with serialization and work with subclasses. Jackson is for JSON serialization specifically, so it may not be what you need. But searching around for terms like "java SQL serialization libraries" may get you some results. – yshavit Oct 06 '17 at 18:32
  • If SQL isn't an option, I did some searching and found this. Could help performance if your map gets exceptionally large. https://stackoverflow.com/questions/1757363/java-hashmap-performance-optimization-alternative – Sarah Oct 06 '17 at 18:36
  • How would `toString()`, `equals()`, `hashCode()` be implemented? Consumers of `Person` would have to do casting/transforming to do anything meaningful. What's wrong with a basic bean? Consumers which don't use some property just never call the setter/getter. What is the concern? – Andrew S Oct 06 '17 at 18:37
  • @AndrewS Exactly, but what if more fields need to be added later? If the object does not contain enough fields for the new user. – ThePirateBae Oct 06 '17 at 18:39
  • @Sarah SQL is an option! – ThePirateBae Oct 06 '17 at 18:40
  • @ThePirateBae - then just add the new fields. There may be some apps which don't need the field so they don't populate or persist a value. Why does that matter? – Andrew S Oct 09 '17 at 12:51

1 Answers1

2

What you are probably doing is making a very common mistake, although there are narrow circumstances under which you could be right.

You perceive that creating a new class is adding complexity and overhead to your application and avoiding creating one is going to make it simpler. This may not be the case, and quite possibly will be the opposite. Classes are there to make life easier: that is why they were invented.

If these fields that you need to add for each branch company require you to write logic that uses them, then you are going to have to extract these fields from the map and put them in a variable and then write some logic to manipulate them. As you don't have a class, you won't have any way of encapsulating that logic (if it makes sense to do so). You will have no way of typing the field (is it a number, a string or a boolean). You won't have any way of knowing whether the Map contains the field other than explicitly checking it. You will have no easy way of seeing what type of map it is. You will have to convert everything.

For example, imagine you need to add an "age" field to your class for a branch. In Java, you create a class for that branch, add an int field and then write your logic for it. You can also use various OO techniques for handling similar classes (e.g., create an interface with getAge() method).

Also, don't assume that extending a class is always the right method of adding extra data. Sometimes having an attached class or classes with associated data is a better approach.

In the Map language you get the String, check if it is there (it might be null) convert it to an int, handle the possible parse exception. All this logic has to float around in some utility class or helper of some sort. It will look awful and you have your temporary int anyway plus you might end up with a helper for the branch logic, which is a class anyway.

The case where your Map might be appropriate is if you are simply just displaying the properties on a screen without doing any logic. In that case, it might be that it is easiest just to use name-value pairs (the general pattern for what you are doing) and write some general logic that can display anything.

Another factor influencing your choice is whether the object is persisted using some Hibernate type thing. If this is the case, then having multiple classes will tend to lead to more database tables (although it can be avoided). This might be good or bad. It will be more complicated for the DBA, but on the other hand, it will be much easier to view and search on branch specific data if it is in proper tables rather than some NVP structure.

In summary: don't assume a solution with more classes is more complicated.

rghome
  • 8,529
  • 8
  • 43
  • 62
  • 1
    Thank you for taking the time to write this out. Currently all the bogus logic is what the application does, everywhere you are flipping between toString(), integer.parseInt()... and then back to strings to set the map. It is cumbersome and very ugly. I was in a discussion with my boss as to why we use a Map for everything he constantly said flexibility. Another reason was reading in parameters from the JSP pages as strings it was easier to store data that way, but i did not think so and was looking for guidance as to which is actually the preferred and performance method. – ThePirateBae Oct 06 '17 at 19:02
  • 1
    I have seen this before. It can be correct, but often, this anti-pattern comes from "lazy architect syndrome". The architect specifies a Map and lists the fields in a Word document with tables for the pseudo-classes and calls it the "interface". You are now basically programming in Word. It's easy for the architect - they don't need to design any software, it doesn't have to compile, it doesn't get syntax checked and it doesn't have to run and it doesn't need to pass any tests. The programmer ends up sorting out the implementation mess, which needs to do all of those things. – rghome Oct 07 '17 at 23:00