Question

As I am maintaining and extend a software system in Java, I saw a colleague (who left due to retirement) implementing a table with a generic approach. This approach is unluckily bound to tables (ui-elements) with a key-value appearance.

For example:

Description   | Value |
--------------|-------|
1             |     1 |
2             |     2 |
3             |     3 |

Means, the description (key of an enum) is bound to a value (stored in the enum). There are multiple (ui-elements) tables, where this approach fits the requirement in an optimal way. Values and description are (as said) stored in enums and read for creating the table (ui-element).

Now, I have to face the situation, that there should be more than one column (of an ui-element table) with values. For example:

Description   | Value1 | Value2  |
--------------|--------|---------|------ 
1             |      1 |       1 |...
2             |      2 |       1 |...
3             |      3 |       1 |...

For the columns (of an ui-element table) applies that they are all similar. The only difference they have is there is an underlying SQL (or an sql string inside the enum) , where for each value for the specific column in the specific row is requested.

So let's say our table (ui-element) defines due to the row a specific animal and due to the column a specific location.
In the specific cell, there is the amount of animals in the zoo for the given animal and location. For example (database sight)

--Value1 1 
SELECT * FROM ZOO WHERE [...] AND **LOCATION = 'CA'**

--Value2 1 
SELECT * FROM ZOO WHERE [...] AND **LOCATION = 'UA'**

Data:

Description| CA | UA  |...
-----------|----|-----|----- 
Turtle     |.3..|  9  |...
Lions      |.6..|  1  |...
Horse      |4.. |  0  |...

This value (for location or the row) is/was constant in the enum and seems to be the breakpoint, breaking this hard-wired construct.

One approach would be to create the same objects in the enum again with passing the location as additional parameter. This way would result in having:

Enum Values(
 - Value1 1_CA
 - Value2 1_UA
)

Which seems to create a big overhead, since the objects only differ in location, but all other parameters are the same.

Another way I thought of was refactoring the enum to an abstract class and derive from it, so that I have the base values and only objects/class like following

  • CA extends BaseClass
  • UA extends BaseClass

However this seems not like a clean approach, more like an "make it any case works" approach. Inheritance would be used in the way it shouldn't be, so I thought of delegation. But for delegation, the BaseClass must be instantiable (which is incorrect too).

How could this problem be solved without breaking the concept of clean OOP?

PS: Has i have slept now one night above this problem, I think i'll use the enum as parameterclass, passing to a separate class (and thus it's constructor) to create the elements in a generic way (by giving the additonal parameter for each row (location)). Because the order is constant, i think this approach will help by solving it this way. If this is the way I can solve it, I will write it as separate problem solution in the comments.

Was it helpful?

Solution

How could this problem be solved without breaking the concept of clean OOP?

This is not an OOP problem. This is a data structure problem.

I know this because there is no behavior associated with this data. If there was we could design objects that would locate that behavior, as methods, with the data. Instead what I see is a desire to have a data structure that can be used to look up these values.

That's what collections are for.

I see two dimensions. If you need to be able to look up individual values by keys into those dimensions then hash tables work fine.

_____|CA|UA|_____
Turtle |.3..| 9 |...
Lions |.6..| 1 |...
Horse |4..| 0 |...

Hash<String, Hash<String, Integer>> zoo = new HashMap<>();

Hash<String, Integer> turtle = new HashMap<>();
turtle.put("CA", 3);
turtle.put("UA", 9);
zoo.put("Turtle", turtle)

Hash<String, Integer> lions = new HashMap<>();
lions.put("CA", 6);
lions.put("UA", 1);
zoo.put("Lions", lions)

Hash<String, Integer> horse = new HashMap<>();
horse.put("CA", 4);
horse.put("UA", 0);
zoo.put("Horse", horse)

log(zoo.get("Horse").get("UA"));

Done this way new zoo locations can be added with ease as well as new animals. If you want type safety you can use enums as the keys rather than strings. But now the enums have to be edited and recompiled every time something new is added. Done with strings your code could actually discover the locations and the animals dynamically.

You might be wondering what value this data structure has over whatever some database framework might have handed you. It's that this is yours. Defined your way. You can write code against it and completely ignore how the framework decided to do it. Only an adapter has to know how to talk to both. Everything else can just assume things are done your way.

Licensed under: CC-BY-SA with attribution
scroll top