Reputation: 436
Sometimes when I design my classes, I need some dependency classes with similar constructor parameters. Assume we have
interface IDependency {
void DoSomething();
}
class DependencyClass : IDependency {
public DependencyClass(int length) {...}
...
}
class MainClass {
public MainClass(int length, IDependency dependency) {...}
...
}
MainClass
needs an instance of DependencyClass
with the same length
. I have two methods in mind to deal with it:
Not creating instances of MainClass
directly and always getting them from a factory. This way I can make sure that the desired IDependency
instance will be provided to MainClass
constructor.
Passing a factory interface, say IDependencyFactory
, to MainClass
constructor instead of IDependency
. So that I can get the desired instance of DependencyClass
within my MainClass
implementation.
I'm not sure if either of them is a good choice. Is there a best practice in this case?
Upvotes: 7
Views: 508
Reputation: 4569
If your length
is runtime variable - refer to this comment.
If you need this in runtime, you can use the solution #2 from this answer.
If it's compile time setting, you can inject it as any other dependency, that's normal that both MainClass
and DependencyClass
are dependent on the same value.
To have a safe compile-time injection, you can introduce something like that:
interface ILength {
int Length { get; }
}
class StaticLength : ILength {
public StaticLength(int length) {
Length = length;
}
}
void Main() {
const int length = 10;
ILength lengthDependency = new StaticLength(length);
IDependency dep = new DependencyClass(lengthDependency);
MainClass mainClass = new MainClass(lengthDependency, dep);
}
And now you can implement any kind of ILength
- read from configuration file, constant, web, mock, calculate base on any other dependency, random etc.
Upvotes: 4
Reputation: 21709
One of the simplest changes you could make to guarantee the length will be the same for both the DepencyClass
and the MainClass
is to add a Length
property to the interface and initialize it from a constructor, and then allow MainClass
to access the length (you then save one parameter on the MainClass
, which is more DRY.
interface IDependency {
int Length { get; }
void DoSomething();
}
class DependencyClass : IDependency {
public DependencyClass(int length) { Length = length; }
...
}
class MainClass {
public MainClass(IDependency dependency) {...}
...
// do something with dependency.Length
}
This does have the possible drawback of "polluting" your interface and perhaps exposing the length to other code. That's up to you if that matters.
Upvotes: 4
Reputation: 10929
This is a very interesting question and the answer lies in what you try to achieve here.
Solution 1. you provided will make your IDependency
the main factory interface, all instanced will be implemented with IDependency
interface which will provide you with a lot of scalability - you will be able to use the IDependency
interface to initialize additional classes in the future with different functionality, which is the classic use and implementation of factory design pattern.
solution 2. you provided will make your MainClass
well, the Main Class of the program, you will handle the instances and their behavior inside the main class and the advantage here is that you can manage all of your instances through IDependency
, and the only thing you do in MainClass
is handle their logic, MinaClass
will be your instances transporter and all of the fundamental changes for the base classes will be made in the interface IDependency
which is a classic solution for Dependency Inversion.
The question still remains, what you are trying to achieve. Consider this question and the two possibilities and you have your answer.
Upvotes: 6