views:

59

answers:

2

There is a class named "Foo" which normally contains more than 100 fields. It's a domain object and I have to customize it for each client because the fields' specification are almost totally different from one client to another (no more than 10 fields are same). Some clients have more than 200 fields.

Currently, I have to update the class definition of "Foo" in IDE as per the specification for each client. Because I have to use these fields in "Foo" to do some calculation in business layer, sometimes it is really error-prone and time-consuming.

I am wondering if someone knows any elegant way to do this? For example, I can write all the fields' definition (name, type, length, default value, scale, precision, calculation formula(mainly +-*/)) outside java code (suppose a xml file), then use a tool to generate the java source code. After that, I just compile and package the generated code as a foo-customized.jar and put it in my application.

+2  A: 

I think you need to take some time and try to better understand (or at least explain) what it is this class is intending to capture. What object in the real world does this class correspond to?

Certainly there are many fields in these 100s of fields that are not actually related to each other, or could be grouped into classes of their own - such as (I would guess) several individual fields which could be grouped into an Address class.

I can't imagine any "object" that truly has 100s of fields/properties.

matt b
@Sagar V @matt bThank you. :)I tried this before. Actually, Foo has several components, such as A, B, C..., the components name itself need not to be changed for each client, but all the fields definitions have to be changed. So grouping these fields or not is the same workload except not OO.
Kevin Yang
_I can't imagine any "object" that truly has 100s of fields/properties._ yeah. I've seen applications where the clients want to hammer in a lot of data and they couldn't care less about structure. They want to do it the way they've always done it, the way that requires the least amount of training. The way that looks like the old paper form. I've had apps that had 100s of fields on them. The client insisted this was what they wanted, and when I delivered they were delighted. /shrug
Tony Ennis
*the components name itself need not to be changed for each client, but all the fields definitions have to be changed* meaning you need to keep changing the fields of the components themselves? It sounds like the data modeled in these components is not abstract enough then. In an ideal world you'd be able to model this data/application in a way that it the structure doesn't change per customer, just the data stored in the classes.
matt b
+2  A: 

Don't generate the Java.

If it's that extreme, do the XML thing to define the appropriate data per customer. Then build Field objects from the XML data. Put them into a Map in Foo. Now instead of foo.getName() you'll use foo.get("name");

Create a Factory that reads the appropriate XML file and returns to you an instance of Foo that's been loaded from the XML.

Trying to put different data into the same class is very unfun.


Or, make concrete classes that are specific to each client. Yes this is tedious but you only have to do it once. These should implement an interface that specifies all the methods needed in the business layer. Now your factory determines which is appropriate, instantiates it, and returns the interface.

Now your business layer is ignorant of the client. That's a good thing.

Now, if your business layer is very dependent on the client then we can do a little more to ease the pain...

Tony Ennis
_Trying to put different data into the same class is very unfun._ I'm not trying to say this is a structural solution - this is a near-hack that may allow you to meet your requirements.
Tony Ennis
Thanks, Tony.The first solution is exactly what I am trying to figure out. I am going to implement a heterogeneous container for this "Foo" which can contains different types of fields.The second solution: interface is good, but in my case, it is really hard to extract an interface that concrete Foos can implement.More thoughts: How can I manage the calculations? Is there any way I can set a formula for one field instead hardcode the calculation in the getter method if the variables in formula only refer to fields of Foo itself?
Kevin Yang
We have two issues. 1. how to handle 100 fields. I think we have that one bludgeoned into submission for now. But, be open-minded about a more concrete solution. 2. How to perform business logic. Now, what sorts of things do you calculate? Do you calculate the value for all clients (perhaps differently, but that's ok...) Where I am going is we're going to need an elegant way to determine which business methods to call.
Tony Ennis
Here is a simple example: Foo has three fields: a, b, c and c = a + b. In my case, Foo can contain 50 uncalculated fields and 50+ calculated fields and the calculated fields are based on those uncalculated ones.I use customized annotations on each field which include the formula (in the Unified Expression Language (EL) format) and then use an ExpressionParser to parse and evaluate this formula. It works fine but all the formulas are hardcoded in java source code and hard to maintain.
Kevin Yang
You just out-tech'ed me EL. Sorry :-D But if there's a formula, then there's going to have to be a formula in one form or another _somewhere_. Are the formulas ever the same (except for the arguments) or are all 50 different? Are they one-liners or complex calculations? Do you always calculate all 50, or are there conditions such that sometimes you do this 20, sometimes that 20, etc?
Tony Ennis
Each calculated field has its own formula and all the formulas are linear (+-*/). Unfortunately, I have to recalculate all the calculated fields at once because when user makes a change on a field, the whole Foo detail page has to be refreshed and some complex business rules should be applied during the process of calculation.
Kevin Yang
Sounds like you're stuck then. Make each a class of type Calc with a method like `public static void calc(Foo foo)`. Associate the classes with the proper XML field config. Now we could create a method in `Field.calc(Foo foo)` that invokes the calc method. For non-calculated fields you could associate a do-nothing class. Now when it's time to calculate you rip down the fields List and do what comes natural.
Tony Ennis
Hmmm could be overkill. The other extreme is just to make a single method that does ALL the calculations in turn.
Tony Ennis
Good idea, worth a try. 1. make Foo, Field, calc, xml config...work; 2. test the performance. < 10ms is acceptable with 50 calculated fields on my 2GHz CPU. All these fields are BigDecimal.
Kevin Yang
Godspeed Kevin. Godspeed.
Tony Ennis