I use a library which I need to patch. I need to fork it because Factory design patter is not used.
Library has that structure: class X that hold references to other classes, that hold references to other classes and few more layers. Class hierarchy is “tree-like” structure.
I look for best way for refactoring – flexible enough to prevent people forking it. I cannot find any best practices on that problem.
Over years I use to solve it by “Injecting Factory” – Factory pattern where parent object is being injected (DI) in factory method. I cannot find any documentation on such approach and I need some feedback on it (e.g. theory or possible problems).
I describe it with an example with Car:
- Car has CarInterior
- CarInterior has Odometer
Problem – no custom objects could be created, especially Odometer.
class Car {
CarInterior interior;
public Car() {
interior = new CarInterior();
}
}
class CarInterior {
Odometer odo;
public CasInterior(){
odo = new Odomether();
}
}
class Odometer {
public Odometer(){}
}
By-book solution using simple Factory methods pattern only (has a limited extendibility)
class Car {
CarInterior interior;
public Car(CarFactory factory) {
interior = createInterior();
}
CarInterior createInterior() { return new CarInterior(); };
}
class CasInterior {
Odometer odo;
public CarInterior(){
odo = createOdometer();
}
CarInterior createOdometer() {
return new Odomether();
}
}
Major problem with this approach
- If factory method needs parameters, that change potentially makes troubles to lib users. Because extending classes should change method definitions.
Minor problems
- if I need to different Odometer, I should extend both Car and CarInterior
- library I need to fork has few “levels” so this means many levels of extra objects till I manage to call The factory method.
Possible Business requests
Possible extension #1 of Odometer class: with KM or Miles
Car object should have targetCountry. If it is in France, Metric units should be used. If in USA – miles. That business request could be implemented in this way:
- (breaking change) factory method createOdometer() gets a param: createOdometer(OdoUnits)
- (breaking change) factory method createInterior() gets a param: createInterior(OdoUnits) or createInterior(Country)
- in case of more levels (my case), more changes are needed
Possible extension #2 of Odometer class: odometer values range
- 0-220 km/h
- 0-300 km/h
- etc
Possible extension #3 of Odometer class: color of odometer should be same as color of the car
If we use same approach, we should introduce more parameters in methods. And more “proxy” functionality.
Questions
So what are best practices for the issue? How could we avoid/reduce method definitions changes while new requirements come?