I just completed a java application using mostly Utility classes, then I read about SOLID principles over the weekend so I'm refactoring the whole application to follow that principle. There's one problem that I encountered while trying it out, therefore, I must be doing it wrong so can anyone lead me to the right path? Example:
public interface ID { }
public class D implements ID {
//this class has a lot of dependencies that I do not want in class B but at some point
// I have to create it. When is that point?
}
public interface IC { }
public class C implements IC {
//this class has a lot of dependencies that I do not want in class B
}
public interface IB { }
public class B implements IB {
public IC c;
public ID d;
// this class depends on the 2 (or more) interfaces IC and ID so
// it won't have dependencies on concrete classes. But if the
// concrete classes are not used, then they all start bubbling up to the
// higher level class (let say class A below), and class A would know about and have
// dependencies on way so many objects, doesn't it?
}
public class A {
ID d = new D();
IC c = new C();
IB b = new B(d, c); // b could given to some other classes
}
As you can see, the more abstract level and the more objects I have, the worse it gets. what is your technique to reduce this?
My first thought is having a client for the interfaces in the middle that knows everything about the concrete classes of those interfaces (kind of like a factory class), then class A would use that client class, but problem still remain. Class A depends on Client class that depends on other concrete classes. I'm just making a longer chain instead of many short chains.
This design looks good to me. There is no need to create further abstraction layers above class A, since that way - as you correctly realised - it would never end. The system must have an edge, abstractions should be resolved in some place. Doing it in class A is fine, as long as this class is only responsible for wiring together the other objects (so you may call class A "Configuration").
So as long as you want to work only with plain java without any frameworks, you are good to go with this design. Using Spring (or any other dependency injection library) for DI may be a plus, but introduce it only if you feel it needed. By the way doing dependency injection with spring's JavaConfig would result in almost the same code as your current class A, with some annotations.