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.

13
  • If you know your keys are always going to be Strings (i.e., "Name," "Height," "Age," etc) you could perhaps do <String, Object>. 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. Commented Oct 6, 2017 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. Commented Oct 6, 2017 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. Commented Oct 6, 2017 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? Commented Oct 6, 2017 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 Commented Oct 6, 2017 at 18:24

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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<String, String> 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.
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.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.