I am trying to identify the pros and cons of two approaches to create an object to return from my generic API. I am thinking the first approach I am sketching out has the advantage of being easier to understand by offshore developers, while the second approach lends itself better to concurrency or more complicated logic on the client side.
Example object model:
class TopLevelResponse {
String field1;
String field2;
MidLevelResponse field3;
ResponseMisc[] field4;
}
class MidLevelResponse {
String field1;
BottomLevelResponse field2;
}
class BottomLevelResponse {
String field1;
String[] field2;
}
class ResponseMisc {
String field1;
String field2;
}
First top-down case where each branching object is created whenever a child field is initialized:
class MyResponseInitializer {
TopLevelResponse rsp;
TopLevelResponse getTopLevelResponse() {
if (Objects.isNull(rsp)) rsp = new TopLevelResponse();
return rsp;
}
MidLevelResponse getMidLevelResponse() {
if (Objects.isNull(getTopLevelResponse().getMidLevelResponse())
getTopLevelResponse().setMidLevelResponse(new MidLevelResponse());
return getTopLevelResponse().getMidLevelResponse();
}
...
void setField1(String val) {
getTopLevelResponse().setField1(val);
}
void setField2(String val) ...
void setMidLevelField1(String val) ...
...
}
And on client side:
...
MyResponseInitializer rspInit = new MyResponseInitializer();
rspInit.setField1("foo");
rspInit.setField2("bar");
rspInit.setMidLevelField1("baz");
...
TopLevelResponse rsp = rspInit.getTopLevelResponse();
Compare to a bottom-up approach like this, where initialization is performed by a series of builders:
static class BottomLevelResponseBuilder(){
...
BottomLevelResponse build()...
}
static class MidLevelResponseBuilder()
...
static class TopLevelResponseBuilder()
...
Which on client side looks like this:
TopLevelResponse rsp = TopLevelResponseBuilder.newInstance()
.field1("foo")
.field2("bar")
.field3(MidLevelResponseBuilder.newInstance()
.field1("baz")...
...
.build();
What are the pros vs cons of either approach here? Am I right to think that the first approach is better from a defensive programming perspective, since it reduces the risk of rogue implementations by offshore devs? Or that using concurrency to create each branch on a separate thread can pay off especially with more nesting involved in the data model if I use approach 2?