I use a third party library. They pass me a POJO that, for our intents and purposes, is probably implemented like this:
public class OurData {
private String foo;
private String bar;
private String baz;
private String quux;
// A lot more than this
// IMPORTANT: NOTE THAT THIS IS A PACKAGE PRIVATE CONSTRUCTOR
OurData(/* I don't know what they do */) {
// some stuff
}
public String getFoo() {
return foo;
}
// etc.
}
For many reasons, including but not limited to encapsulating their API and facilitating unit testing, I want to wrap their data. But I don't want my core classes to be dependent on their data (again, for testing reasons)! So right now I have something like this:
public class DataTypeOne implements DataInterface {
private String foo;
private int bar;
private double baz;
public DataTypeOne(String foo, int bar, double baz) {
this.foo = foo;
this.bar = bar;
this.baz = baz;
}
}
public class DataTypeTwo implements DataInterface {
private String foo;
private int bar;
private double baz;
public DataTypeOne(String foo, int bar, double baz, String quux) {
this.foo = foo;
this.bar = bar;
this.baz = baz;
this.quux = quux;
}
}
And then this:
public class ThirdPartyAdapter {
public static makeMyData(OurData data) {
if(data.getQuux() == null) {
return new DataTypeOne(
data.getFoo(),
Integer.parseInt(data.getBar()),
Double.parseDouble(data.getBaz()),
);
} else {
return new DataTypeTwo(
data.getFoo(),
Integer.parseInt(data.getBar()),
Double.parseDouble(data.getBaz()),
data.getQuux();
);
}
}
This adapter class is coupled with the other few classes that MUST know about the third party API, limiting it's pervasiveness through the rest of my system. However... this solution is GROSS! In Clean Code, page 40:
More than three arguments (polyadic) requires very special justification--and then shouldn't be used anyway.
Things I've considered:
- Creating a factory object rather than a static helper method
- Doesn't solve the problem of having a bajillion arguments
- Creating a subclass of DataTypeOne and DataTypeTwo that has a dependent constructor
- Still has a polyadic protected constructor
- Create entirely separate implementations that conform to the same interface
- Multiple of the above ideas simultaneously
How should this situation be handled?
Note this is not an anti-corruption layer situation. There's nothing wrong with their API. The problems are:
- I don't want MY data structures to have
import com.third.party.library.SomeDataStructure;
- I can't construct their data structures in my test cases
- My current solution results in very very high argument counts. I want to keep argument counts low, WITHOUT passing in their data structures.
- That question is "what is a anti corruption layer?". My question is "how can I use a pattern, any pattern, to solve this scenario?"
I'm not asking for code, either (otherwise this question would be on SO), just asking for enough of an answer to enable me to write the code effectively (which that question does not provide).
The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. More than three (polyadic) requires very special justification — and then shouldn’t be used anyway.