0

I have these classes and I want to instantiate each one of them easily.

All the data to create them are in a json file and there will be a lot of different objects in the end. Each objects have a lot of attributes, I would prefer using a helper. A, B and C can be instantiated and used separately even if A might depend on a C object (or B).

enter image description here

First I thought that a factory method would suffice.But each one of them has a lot of attributes and since A depends on all the other objects it would be a mess.

Then I thought that a pseudo-Builder would work best since it would let me set every attribute one by one while I parse the json file. This works but it means that every class has its own builder and I would need to handle the builders dependency when I parse everything.

There are solutions but I would like to find something more elegant and not create objects that I don't need. The other thing is that the parser is Abstract and implemented by the one using the library (needed for several reasons).

My current solution is a pseudo-builder (simple inner-class that lets me setAtt1(...).setAtt2(...)...Build()) for each class and one Factory that has createA(id), CreateB(id), CreateC(id) and an actual builder pattern for H1,H2,H3. The Factory is a realization of the Abstract JsonParser class that the user needs to implement thanks to the Builders.

I'm not looking for the definitive solution but I would like some advice on my solution and if I am making a big mistake on how I handle things.

4
  • Not relevant, but there is an inconsistency in using UML composition twice for F : composition implies a non-shared ownership and control of lifecycle. So better use an aggregation (or even a simple association between B and F. – Christophe May 5 '20 at 17:45
  • @Christophe I understand what you mean but in this specific case one Object F cannot be part of B and C at the same time. I just don't know how to show this with UML – rXp May 6 '20 at 17:39
  • a white diamond (aggregation) instead of a full black one(composition) should solve the UML part :-) – Christophe May 6 '20 at 17:51
  • Yet another question that mixes problems. Does it change anything at all if the input comes from XML-file? Or from database? No. You know the input is structured, so you can recreate it as-is. The real problem is how do you re-organize it (maybe with repetitions) and represent it in proper way, SoC. I would say, whatever produce short, robust code. But I don't include this pseudo-builder at all, because if this is just a setter in disguise it it not builder at all, it is just a setter, and secondly you make your data mutable just in sake of creating it. Very high price with little benefit. – greenoldman May 9 '20 at 5:48
1

This problem is reminiscent of the old XML configuration files that used to wire components together in the early to mid 2000s. The basic approach was rather simple:

  • XML Elements were mapped to objects (usually by some sort of lookup table, or special attributes that had the class name)
  • XML Attributes were mapped to properties (getters/setters) on the object

Microsoft's XAML also falls in this pattern, but they have provided a means of expressing attributes as elements as well to handle complex values.

The main thing I would look at is keeping a good separation of concerns:

  • Parser: Simply use the parser that you know how to work with
  • Object Mapper: Takes the results of the parser and calls the factory
  • Factory: Creates instances of the objects you need
  • Resolver: If objects need to be wired together, the resolver finds the instance that is needed
  • Registry: The registry of processed objects

This distribution of responsibilities helps each class be focused on one part of the process, making it easier to maintain. The Parser has the simplest job, rendering the text into a set of objects that can be traversed. The object mapper then takes that tree of objects and calls the Resolver to either look the object up from the registry, or build the object from the factory (the raw object gets added to the registry at that time). The object mapper then attempts to set the properties as needed.

The approach allows you to declare objects in one place, but reference them in another place.

You really need a simple set of rules to make this work:

  • You only need one factory if objects can be created with an empty constructor
  • Properties (getters/setters) must be publicly accessible

You can use a reflection API to actually perform the setting and getting. That allows you to iterate over the attributes in your file and map them to object properties with one mapper. Reflection is typically slower, but if this is something that gets built up once and re-used then that speed penalty is probably worth avoiding the headaches of writing 1 factory per object.


Evolution of parsing to improve memory and maintain usability

There were a couple standards back then that helped minimize memory overhead during this process. It was clear that the Document Object Model (DOM) parsing wasn't going to scale for very large complex systems. That introduced the Simple API for XML (SAX) parsers that called methods to signify the begin and end of objects. This approach also worked well.

The last evolution, may be what you are looking for. That's the Streaming API for XML (StAX). The key difference here is that it combined the memory efficiency of SAX parsers, with the ease of use of working with a DOM.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.