Doesn't Dependency Injection simply move the issue elsewhere? - c#

So Dependency Injection is recommended usually to help with unit testing, to solve the problem of having a class dependent on other classes. This sounds great, but let me walk through the issue I'm facing.
Here is a regular implementation without DI:
class Upper{
Middle middle = new Middle();
}
class Middle{
Lower lower = new Lower();
}
class Lower{
}
Now let's start at the bottom. Middle depends on Lower, we don't really want that, so we'll create a redundant interface for Lower and pass that to the constructor of Middle instead:
class Middle{
Lower lower;
public Middle(ILower lower){
this.lower = lower;
}
}
interface ILower{
}
class Lower : ILower{
}
Well this sounds great, right? Well not really. Most examples I've seen stop here, forgetting that something needs to use the class Middle. Now we have to update Upper to be compatible:
class Upper{
Middle middle = new Middle(new Lower());
}
This doesn't seem very useful... All that we've done is moved the problem up a level, and created an unusual dependency: Upper depends on Lower now? That's definitely not an improvement.
I must be missing the benefit, but it seems like DI just moved the issue rather than solved it. In fact, it also makes the code harder to understand.
Also, here is a "full" implementation:
interface IUpper {
}
class Upper : IUpper {
Middle middle;
public Upper(IMiddle middle){
this.middle = middle;
}
}
interface IMiddle {
}
class Middle : IMiddle {
Lower lower;
public Middle(ILower lower){
this.lower = lower;
}
}
interface ILower {
}
class Lower : ILower {
}
But again, I'm just moving the problem. To use Upper, I need:
new Upper(new Middle(new Lower()));
and now I depend on 3 classes!

Dependency injection simply refers to the way you create classes, so that their dependencies are provided for them ("injected" into them) instead of classes creating instances of their own dependencies.
Does DI just move the problem of creating class instances somewhere else?
Yes, that's exactly what it does, and that's good.
Every class instance that you use has to be instantiated somewhere. The question is where that instantiation takes place, and whether it makes your classes more or less manageable and testable.
The trade-off is that if one class directly creates instances of other classes it depends on, then sure, calling the constructor for that outer class is much simpler. You create that class, and it creates a bunch of other classes, and they create more classes, and so on. But each class that directly creates other classes becomes harder and harder to unit test. You can't write a test for just the behavior of one class when that behavior includes the behavior of the classes it creates, the classes they create, and so on. So in return for simpler constructor calls, you get code which is just about impossible to test and also very difficult to maintain.
Dependency injection moves creation of a class's dependencies out of the class. That makes each individual class easier to test and maintain, but it creates a different problem, as you've observed. Now your constructor calls are much more complicated, creating all sorts of nested dependencies.
What solves that problem is a dependency injection container, also called an IoC container. Some examples are Windsor, Autofac, Unity, and there are many more. With these, you simply specify an implementation for each individual interface on which any class might depend.
For example (this is Windsor syntax, but they're all somewhat similar)
container.Register(Component.For<InterfaceA, ImplementationToUse>());
container.Register(Component.For<InterfaceB, ImplementationForThis>());
container.Register(Component.For<InterfaceC, ImplementationToUse>());
Then, if you call
var thingINeed = container.Resolve<InterfaceA>();
(That's not actually how we get a class instance from a container, but that's another story.)
It's going to figure out which classes it needs to create to pass the the constructor of the implementation. If those classes have more dependencies, it will create those, and so on, and so on.
So now you've got the best of both worlds. You can create as many small, testable classes as you want, with tons of nested dependencies, all depending on abstractions. If you were to try to call their constructors directly it would be insanely complicated, way beyond the example in your question. But you don't have to do that. You can just think of each class individually - what does it do, and what interfaces does it directly depend on?
You still have some complexity. Instead of calling a bunch of constructors you now have to register individual dependencies with a container. But it's a good trade-off, and you come out ahead because your classes are decoupled and testable.

When you inject dependencies, you are not exempt from the need to instantiate classes. You take the creation of dependencies out of dependent classes so that they do not depend on their specific implementation (calling the constructor of the aggregated class).
Yes, putting dependencies on the upper level, you get this line:
new Upper(new Middle(new Lower()));
To create an object, you need to resolve the tree of its dependencies. To facilitate this work, there are many IoC containers. They allow you to reduce the recording to this:
var upper = iocContainer.resolve<IUpperInterface>();
As advantages, you get class testability, flexibility and re-useability.

Related

IoC containers: slightly differ the structure of instance created

I am studying IoC, DDD and AOP concepts. I've read a number of articles, docs, Ninject manual (i'm restricted to use .NET 3.5), tried some stuff and so on.
It's hard to shove everything at once to my head, but motivation, concepts and technical matters are somewhat clear. And i'd been always feeling that i was missing something.
Firstly, as i understand IoC containers' purpose is initial object structure set up?
Like, set up container in composition root, create "main" object, that is being wired all the way by IoC container.
Then, as i understand, later all objects are instantiated with factories? Although i can't help myself to perceive factory as a case of service locator (that ended up considered antipattern and by the way is used as core mechanics of IoC containers).
So the question is:
What if i want to create an instance with slightly different structure, e.g. i have
interface IFoo{}
interface IBar{}
class SomeClass
{
SomeClass(IFoo obj){...}
}
class Foo : IFoo
{
Foo(IBar obj){...}
}
class Bar : IBar
{
}
class FooBar : IBar // also implements IBar interface
{
}
So, initial binding configuration is making SomeClass.Foo.Bar structure. Assume, i also need SomeClass.Foo.FooBar. What do i do? The options i can think of:
reconfigure bindings 'in place': just no.
have a constructor parameter for top class, that has configuration for whole structure. that's pretty awful. aside from the fact that all subsequent constructors (and all other project classes constructors, in the end, i'm sure) will have to have one more parameter, it is not clearly seen, how it will function and not use some dirty tricks.
substitute what is needed after object was created. it either breaks law of demeter (about which i'm not concerned too much, but in this case it's too rude) and a couple of other principles or, in general case, isn't possible at all.
use factory that is configured somehow. it just defers/transfers the need itself to later/other place in code
use some kind of contextual/conventional binding. one solution i see (didn't test yet) it's to go all the way to the top of "activation root", check, what's creating the hierarchy. m.b. we'll have to make decorator for top level class, for container to check its type and behave accordingly. actually, container may be configured in a manner, that it decides, what concrete instance to inject by "parsing" top level interface's name. something like
ICfg_ConcreteType1_ConcreteType2_...
the problems here (besides that it looks like hack):
a) we must introduce some mnemonic system, which is not obscene/user friendly.
b) we must have rules/decorators for every factory with this "feature" (but looks like we can somewhat simplify the process at least with rules)
c) it resembles me of reflection usage with convention over configuration, which i'm averted of and treat it as a hack.
Or we may use attributes to set this up. Or may be i just don't know something.
Firstly, as i understand IoC containers' purpose is initial object structure set up?
Forget about IoC containers for a moment. Dependency Injection is not about using tools. It's first and foremost about applying principles and patterns. The driving force behind Dependency Injection are the SOLID principles. I would even go as far as start your application without using an IoC container at all, and only start using one when is a really compelling reason to do so. This means that you simply build up the object graphs by hand. The right place to do this is in your Composition Root. This should be the single place where you compose your object graphs.
And do note that this advice comes from someone who is building and maintaining a IoC container himself.
Then, as i understand, later all objects are instantiated with factories?
When practicing Dependency Injection, you will see that the need to use factories actually minimizes. They can still be useful, but I only use them sparingly nowadays.
Reason for this is that a factory usually just adds an extra (useless) layer of abstraction.
When starting with making code more loosely coupled, developers are tempted to use a factory as follows:
public class SomeClass
{
public void HandleSomething() {
IFoo foo = FooFactory.Create();
foo.DoSomething();
}
}
Although this allows a Foo implementation to be decoupled from SomeClass, SomeClass still takes a strong dependency on FooFactory. This still makes SomeClass hard to test, and lowers reusability.
After experiencing such a problem, developers often start to abstract away the FooFactory class as follows:
public class SomeClass
{
private readonly IFooFactory fooFactory;
public SomeClass(IFooFactory fooFactory) {
this.fooFactory = fooFactory;
}
public void HandleSomething() {
IFoo foo = this.fooFactory.Create();
foo.DoSomething();
}
}
Here a IFooFactory abstraction is used, which is injected using constructor injection. This allows SomeClass to be completely loosely coupled.
SomeClass however now has two external dependencies. It both knows about IFooFactory and IFoo. This duplicates the complexity of SomeClass, while there is no compelling reason to do so. We will immediately notice this increase of complexity when writing unit tests. We will now suddenly have to mock two different abstactions and test them both.
Since we are practicing constructor injection here, we can simplify SomeClass -without any downsides- to the following:
public class SomeClass
{
private readonly IFoo foo;
public SomeClass(IFoo foo) {
this.foo = foo;
}
public void HandleSomething() {
this.foo.DoSomething();
}
}
Long story short, although the Factory design pattern is still valid and useful, you will hardly ever need it for retrieving injectables.
Although i can't help myself to perceive factory as a case of service locator
No. A factory is not a service Locator. The difference between a factory and a locator is that with a factory you can build up only one particular type of objects, while a locator is untyped. You can build up anything. If you use an IoC container however, you will often see that the factory implementation will forward the request to the container. This should not be a problem, because your factory implementation should be part of your composition root. The composition root always depends on your container and this is not a form of Service Location, as Mark Seemann explains here.
Or we may use attributes to set this up. Or may be i just don't know something.
Refrain from using attributes for building up object graphs. Attributes pollute your code base and cause a hard dependency on an underlying technology. You absolutely want your application to stay oblivious to any used composition tool. As I started with, you might not even use any tool at all.
For instance, your object graph can be composed quite easily as follows:
new SomeClass(
new Foo(
new Bar()));
In your example, you seem to have two IBar implementations. From the context it is completely unclear what the function of this abstraction and these implementations are. I assume that you want to be able to switch implementations one some runtime condition. This can typically be achieved by using a proxy implementation. In that case your object graph would look as follows:
new SomeClass(
new Foo(
new BarProxy(
new Bar(),
new FooBar()));
Here BarProxy looks as follows:
public class BarProxy
{
private readonly IBar left;
private readonly IBar right;
public BarProxy(IBar left, IBar right) {
this.left = left;
this.right = right;
}
public void BarMethod(BarOperation op) {
this.GetBar(op).BarMethod(op);
}
private IBar GetBar(BarOperation op) {
return op.SomeValue ? this.left : this.right;
}
}
It's hard to say when you should start using a DI container. Some people like to stay away from DI containers almost always. I found that for the type of applications I build (that are based on these and these patterns), a DI container becomes really valuable, because it saves you from having to constantly update your Composition Root. In other words:
Dependency Injection and the SOLID principles help making your application maintainable. A DI library will help in making your composition root maintainable, but only after you made your application maintainable using SOLID and DI.
You would generally use some sort of tag system.
http://www.ghij.org/blog/post/2014/05/19/how-to-tag-classes-to-determine-which-to-reflect-with-mef.aspx

Is there an alternative to bastard injection? (AKA poor man's injection via default constructor)

I most commonly am tempted to use "bastard injection" in a few cases. When I have a "proper" dependency-injection constructor:
public class ThingMaker {
...
public ThingMaker(IThingSource source){
_source = source;
}
But then, for classes I am intending as public APIs (classes that other development teams will consume), I can never find a better option than to write a default "bastard" constructor with the most-likely needed dependency:
public ThingMaker() : this(new DefaultThingSource()) {}
...
}
The obvious drawback here is that this creates a static dependency on DefaultThingSource; ideally, there would be no such dependency, and the consumer would always inject whatever IThingSource they wanted. However, this is too hard to use; consumers want to new up a ThingMaker and get to work making Things, then months later inject something else when the need arises. This leaves just a few options in my opinion:
Omit the bastard constructor; force the consumer of ThingMaker to understand IThingSource, understand how ThingMaker interacts with IThingSource, find or write a concrete class, and then inject an instance in their constructor call.
Omit the bastard constructor and provide a separate factory, container, or other bootstrapping class/method; somehow make the consumer understand that they don't need to write their own IThingSource; force the consumer of ThingMaker to find and understand the factory or bootstrapper and use it.
Keep the bastard constructor, enabling the consumer to "new up" an object and run with it, and coping with the optional static dependency on DefaultThingSource.
Boy, #3 sure seems attractive. Is there another, better option? #1 or #2 just don't seem worth it.
As far as I understand, this question relates to how to expose a loosely coupled API with some appropriate defaults. In this case, you may have a good Local Default, in which case the dependency can be regarded as optional. One way to deal with optional dependencies is to use Property Injection instead of Constructor Injection - in fact, this is sort of the poster scenario for Property Injection.
However, the real danger of Bastard Injection is when the default is a Foreign Default, because that would mean that the default constructor drags along an undesirable coupling to the assembly implementing the default. As I understand this question, however, the intended default would originate in the same assembly, in which case I don't see any particular danger.
In any case you might also consider a Facade as described in one of my earlier answers: Dependency Inject (DI) "friendly" library
BTW, the terminology used here is based on the pattern language from my book.
My trade-off is a spin on #BrokenGlass:
1) Sole constructor is parameterized constructor
2) Use factory method to create a ThingMaker and pass in that default source.
public class ThingMaker {
public ThingMaker(IThingSource source){
_source = source;
}
public static ThingMaker CreateDefault() {
return new ThingMaker(new DefaultThingSource());
}
}
Obviously this doesn't eliminate your dependency, but it does make it clearer to me that this object has dependencies that a caller can deep dive into if they care to. You can make that factory method even more explicit if you like (CreateThingMakerWithDefaultThingSource) if that helps with understanding. I prefer this to overriding the IThingSource factory method since it continues to favor composition. You can also add a new factory method when the DefaultThingSource is obsoleted and have a clear way to find all the code using the DefaultThingSource and mark it to be upgraded.
You covered the possibilities in your question. Factory class elsewhere for convenience or some convenience within the class itself. The only other unattractive option would be reflection-based, hiding the dependency even further.
One alternative is to have a factory method CreateThingSource() in your ThingMaker class that creates the dependency for you.
For testing or if you do need another type of IThingSource you would then have to create a subclass of ThingMaker and override CreateThingSource() to return the concrete type you want. Obviously this approach only is worth it if you mainly need to be able to inject the dependency in for testing, but for most/all other purposes do not need another IThingSource
I vote for #3. You'll be making your life--and the lives of other developers--easier.
If you have to have a "default" dependency, also known as Poor Man’s Dependency Injection, then you have to initialize and "wire" the dependency somewhere.
I will keep the two constructors but have a factory just for the initialization.
public class ThingMaker
{
private IThingSource _source;
public ThingMaker(IThingSource source)
{
_source = source;
}
public ThingMaker() : this(ThingFactory.Current.CreateThingSource())
{
}
}
Now in the factory create the default instance and allow the method to be overrided:
public class ThingFactory
{
public virtual IThingSource CreateThingSource()
{
return new DefaultThingSource();
}
}
Update:
Why using two constructors:
Two constructors clearly show how the class is intended to be used. The parameter-less constructor states: just create an instance and the class will perform all of it's responsibilities. Now the second constructor states that the class depends of IThingSource and provides a way of using an implementation different than the default one.
Why using a factory:
1- Discipline: Creating new instances shouldn't be part of the responsibilities of this class, a factory class is more appropriate.
2- DRY: Imagine that in the same API other classes also depend on IThingSource and do the same. Override once the factory method returning IThingSource and all the classes in your API automatically start using the new instance.
I don't see a problem in coupling ThingMaker to a default implementation of IThingSource as long as this implementation makes sense to the API as a whole and also you provide ways to override this dependency for testing and extension purposes.
You are unhappy with the OO impurity of this dependency, but you don't really say what trouble it ultimately causes.
Is ThingMaker using DefaultThingSource in any way that does not conform to IThingSource? No.
Could there come a time where you would be forced to retire the parameterless constructor? Since you are able to provide a default implementation at this time, unlikely.
I think the biggest problem here is the choice of name, not whether to use the technique.
The examples usually related to this style of injection are often extremely simplisitic: "in the default constructor for class B, call an overloaded constructor with new A() and be on your way!"
The reality is that dependencies are often extremely complex to construct. For example, what if B needs a non-class dependency like a database connection or application setting? You then tie class B to the System.Configuration namespace, increasing its complexity and coupling while lowering its coherence, all to encode details which could simply be externalized by omitting the default constructor.
This style of injection communicates to the reader that you have recognized the benefits of decoupled design but are unwilling to commit to it. We all know that when someone sees that juicy, easy, low-friction default constructor, they are going to call it no matter how rigid it makes their program from that point on. They can't understand the structure of their program without reading the source code for that default constructor, which isn't an option when you just distribute the assemblies. You can document the conventions of connection string name and app settings key, but at that point the code doesn't stand on its own and you put the onus on the developer to hunt down the right incantation.
Optimizing code so those who write it can get by without understanding what they are saying is a siren song, an anti-pattern that ultimately leads to more time lost in unraveling the magic than time saved in initial effort. Either decouple or don't; keeping a foot in each pattern diminishes the focus of both.
For what it is worth, all the standard code I've seen in Java does it like this:
public class ThingMaker {
private IThingSource iThingSource;
public ThingMaker() {
iThingSource = createIThingSource();
}
public virtual IThingSource createIThingSource() {
return new DefaultThingSource();
}
}
Anybody who doesn't want a DefaultThingSource object can override createIThingSource. (If possible, the call to createIThingSource would be somewhere other than the constructor.) C# does not encourage overriding like Java does, and it might not be as obvious as it would be in Java that the users can and perhaps should provide their own IThingSource implementation. (Nor as obvious how to provide it.) My guess is that #3 is the way to go, but I thought I would mention this.
Just an idea - perhaps a bit more elegant but sadly doesn't get rid of the dependency:
remove the "bastard constructor"
in the standard constructor you make the source param default to null
then you check for source being null and if this is the case you assign it "new DefaultThingSource()" otherweise whatever the consumer injects
Have an internal factory (internal to your library) that maps the DefaultThingSource to IThingSource, which is called from the default constructor.
This allows you to "new up" the ThingMaker class without parameters or any knowledge of IThingSource and without a direct dependency on DefaultThingSource.
For truly public APIs, I generally handle this using a two-part approach:
Create a helper within the API to allow an API consumer to register "default" interface implementations from the API with their IoC container of choice.
If it is desirable to allow the API consumer to use the API without their own IoC container, host an optional container within the API that is populated the same "default" implementations.
The really tricky part here is deciding when to activate the container #2, and the best choice approach will depend heavily on your intended API consumers.
I support option #1, with one extension: make DefaultThingSource a public class. Your wording above implies that DefaultThingSource will be hidden from public consumers of the API, but as I understand your situation there's no reason not to expose the default. Furthermore, you can easily document the fact that outside of special circumstances, a new DefaultThingSource() can always be passed to the ThingMaker.

Where do I put all these interfaces?

I'm trying to get my feet wet with unit testing. I'm currently not in the habit of writing interfaces for classes unless I foresee some reason I would need to swap in a different implementation. Well, now I foresee a reason: mocking.
Given that I'm going to be going from just a handful of interfaces to perhaps hundreds, the first thing that popped into my head was, Where should I put all these interfaces? Do I just mix them in with all the concrete implementations or should I put them in a sub-folder. E.g., should controller interfaces go in root/Controllers/Interfaces, root/Controllers, or something else entirely? What do you advise?
Before I discuss organization:
Well, now I foresee a reason: mocking.
You can mock with classes, as well. Subclassing works well for mocking as an option instead of always making interfaces.
Interfaces are incredibly useful - but I would recommend only making an interface if there is a reason to make an interface. I often see interfaces created when a class would work fine and be more appropriate in terms of logic. You shouldn't need to make "hundreds of interfaces" just to allow yourself to mock out implementations - encapsulation and subclassing works quite well for that.
That being said - I typically will organize my interfaces along with my classes, as grouping related types into the same namespaces tends to make the most sense. The main exception is with internal implementations of interfaces - these can be anywhere, but I will sometimes make an "Internal" folder + an Internal namespace that I use specifically for "private" interface implementations (as well as other classes that are purely internal implementation). This helps me keep the main namespace uncluttered, so the only types are the main types relating to the API itself.
Here's a suggestion, if almost all of your interfaces are to support only one class, just add the interface to the same file as the class itself under the same namespace. That way you don't have a separate file for the interface which could really clutter the project or need a sub folder just for interfaces.
If you find yourself creating different classes using the same interface, I would break the interface out into the same folder as the class unless it becomes completely unruly. But I don't think that would happen because I doubt you have hundreds of class files in the same folder. If so, that should be cleaned up and subfoldered according to functionality and the rest will take care of itself.
Coding to interfaces goes far beyond being able to test code. It creates flexibility in the code allowing a different implementation to be swapped in or out depending on product requirements.
Dependency Injection is another good reason to code to interfaces.
If we have an object called Foo that is used by ten customers and now customer x wants to have Foo work in a different way. If we have coded to an interface (IFoo) we just need to implement IFoo to the new requirements in CustomFoo. As long as we don't change IFoo there is not much needed. Customer x can use the new CustomFoo and other customers can continue to use old Foo and there need be few other code changes to accommodate.
However the point I really wanted to make is that interfaces can help eliminate circular references. If we have an object X that has a dependency on object Y and object Y has a dependency on object X. We have two options 1. with object x and y have to be in the same assembly or 2. we have to find some way of breaking the circular reference. We can do this by sharing interfaces rather than sharing implementations.
/* Monolithic assembly */
public class Foo
{
IEnumerable <Bar> _bars;
public void Qux()
{
foreach (var bar in _bars)
{
bar.Baz();
}
}
/* rest of the implmentation of Foo */
}
public class Bar
{
Foo _parent;
public void Baz()
{
/* do something here */
}
/* rest of the implementation of Bar */
}
If foo and bar have completely different uses and dependencies we probably do not want them in the same assembly especially if that assembly is already large.
To do this we can create an interface on one of the classes, say Foo, and refer to the interface in Bar. Now we can put the interface in a third assembly shared by both Foo and Bar.
/* Shared Foo Assembly */
public interface IFoo
{
void Qux();
}
/* Shared Bar Assembly (could be the same as the Shared Foo assembly in some cases) */
public interface IBar
{
void Baz();
}
/* Foo Assembly */
public class Foo:IFoo
{
IEnumerable <IBar> _bars;
public void Qux()
{
foreach (var bar in _bars)
{
bar.Baz();
}
}
/* rest of the implementation of Foo */
}
/* Bar assembly */
public class Bar:IBar
{
IFoo _parent;
/* rest of the implementation of Bar */
public void Baz()
{
/* do something here */
}
I think there is also an argument for maintaining the interfaces separate from their implementations and treating these sightly differently in the release cycle as this allows interoperability between components that were not all compiled against the same sources. If fully coding to interfaces and if interfaces can only be changed for major version increments and not on minor version increments then any component components of the same major version should work with any other component of the same major version regardless of the minor version.
This way you can have a library project with a slow release cycle containing just interfaces, enums and exceptions.
It depends. I do this: If you have to add a dependent 3rd party assembly, move the concrete versions out to a different class library. If not, they can stay side byside in the same directory and namespace.
I find that when I need hundreds of interfaces in my project to isolate dependencies, I find that there may be an issue in my design. This is especially the case when a lot of these interfaces end up having only one method. An alternative to doing this is to have your objects raise events and then bind your dependencies to those events. For an example, let's say you want to mock out persisting your data. One perfectly reasonable way to do this would be to do this:
public interface IDataPersistor
{
void PersistData(Data data);
}
public class Foo
{
private IDataPersistor Persistor { get; set; }
public Foo(IDataPersistor persistor)
{
Persistor = persistor;
}
// somewhere in the implementation we call Persistor.PersistData(data);
}
Another way you could do this without using interfaces or mocks would be do do this:
public class Foo
{
public event EventHandler<PersistDataEventArgs> OnPersistData;
// somewhere in the implementation we call OnPersistData(this, new PersistDataEventArgs(data))
}
Then, in our test, you can instead of creating a mock do this:
Foo foo = new Foo();
foo.OnPersistData += (sender, e) => { // do what your mock would do here };
// finish your test
I find this to be cleaner than using mocks excessively.
I disagree quite a bit with the Accepted answer.
1: While technically correct, you do not NEED an interface because you have the option to mock a concrete implementation, you should make an interface for 2 reasons.
You can extend your code with an interface, concrete implementations require modification, if you do not have an extension, once you get a change request.
1.1:
You can make TDD(Test driven development) without any actual implemented code, as long as you only create interfaces to test. This will also force you to consider code design before you make an implementation. Which is an excellent approach to coding.
1.2:
but I would recommend only making an interface if there is a reason to make an interface. I often see interfaces created when a class would work fine and be more appropriate in terms of logic.
There is always a reason to make an interface. Because SOLID's open/close principle says you should aim for extending your code rather than modifying it.
And this is true for multiple reasons.
1.2.1:
It's easier to write new unit tests this way. You will only need the dependency to the concrete implementation you are testing in your code as a subject. (And before you have a concrete implementation you can use a mock)
1.2.2:
When you have a concrete implementation, the reference to that concrete implementation will be propagated throughout the system. With an interface, all references will be done by interface, not concrete implementation. This makes extension possible.
1.2.3
If you follow up with all "leaf" piece of code, to follow the principle, if the method has a return, the method can't have a side effect, if the method doesn't have a return, it can only have 1 side effect, you will also automatically split your code up into the "S" part of SOLID, this makes your unit tests small, and very easy to maintain.
2:
Interfaces are technically needed, if you want to write clean code. If you want to follow SOLID, I don't see how you can do it, without interfaces.
You will also need to organize your code efficiently when you break about responsibilities, as the more decoupled your code is, the more interfaces and implementations of interfaces, you will have. Thus you need to have a good project management system in place, so you don't have "hundres of interfaces" lying around randomly.
There are so very good guides in books and youtube, udemy, etc. That will teach you this. (and also some poor ones, basically, they increase in usefulness when you have to pay for them in general). You will have to know enough about the subject matter to identify if a free one is good enough, if you plan to make business decision on it, before you do so, at least.

Strategy pattern and "action" classes explosion

Is it bad policy to have lots of "work" classes(such as Strategy classes), that only do one thing?
Let's assume I want to make a Monster class. Instead of just defining everything I want about the monster in one class, I will try to identify what are its main features, so I can define them in interfaces. That will allow to:
Seal the class if I want. Later, other users can just create a new class and still have polymorphism by means of the interfaces I've defined. I don't have to worry how people (or myself) might want to change/add features to the base class in the future. All classes inherit from Object and they implement inheritance through interfaces, not from mother classes.
Reuse the strategies I'm using with this monster for other members of my game world.
Con: This model is rigid. Sometimes we would like to define something that is not easily achieved by just trying to put together this "building blocks".
public class AlienMonster : IWalk, IRun, ISwim, IGrowl {
IWalkStrategy _walkStrategy;
IRunStrategy _runStrategy;
ISwimStrategy _swimStrategy;
IGrowlStrategy _growlStrategy;
public Monster() {
_walkStrategy = new FourFootWalkStrategy();
...etc
}
public void Walk() { _walkStrategy.Walk(); }
...etc
}
My idea would be next to make a series of different Strategies that could be used by different monsters. On the other side, some of them could also be used for totally different purposes (i.e., I could have a tank that also "swims"). The only problem I see with this approach is that it could lead to a explosion of pure "method" classes, i.e., Strategy classes that have as only purpose make this or that other action. In the other hand, this kind of "modularity" would allow for high reuse of stratagies, sometimes even in totally different contexts.
What is your opinion on this matter? Is this a valid reasoning? Is this over-engineering?
Also, assuming we'd make the proper adjustments to the example I gave above, would it be better to define IWalk as:
interface IWalk {
void Walk();
}
or
interface IWalk {
IWalkStrategy WalkStrategy { get; set; } //or something that ressembles this
}
being that doing this I wouldn't need to define the methods on Monster itself, I'd just have public getters for IWalkStrategy (this seems to go against the idea that you should encapsulate everything as much as you can!)
Why?
Thanks
Walk, Run, and Swim seem to be implementations rather than interfaces. You could have a ILocomotion interface and allow your class to accept a list of ILocomotion implementations.
Growl could be an implementation of something like an IAbility interface. And a particular monster could have a collection of IAbility implementations.
Then have an couple of interfaces that is the logic of which ability or locomotion to use: IMove, IAct for example.
public class AlienMonster : IMove, IAct
{
private List<IAbility> _abilities;
private List<ILocomotion> _locomotions;
public AlienMonster()
{
_abilities = new List<IAbility>() {new Growl()};
_locomotion = new List<ILocomotion>() {new Walk(), new Run(), new Swim()}
}
public void Move()
{
// implementation for the IMove interface
}
public void Act()
{
// implementation for the IAct interface
}
}
By composing your class this way you will avoid some of the rigidity.
EDIT: added the stuff about IMove and IAct
EDIT: after some comments
By adding IWalk, IRun, and ISwim to a monster you are saying that anything can see the object should be able to call any of the methods implemented in any of those interfaces and have it be meaningful. Further in order for something to decide which of the three interfaces it should use you have to pass the entire object around. One huge advantage to using an interface is that you can reference it by that interface.
void SomeFunction(IWalk alienMonster) {...}
The above function will take anything that implements IWalk but if there are variations of SomeFunction for IRun, ISwim, and so on you have to write a whole new function for each of those or pass the AlienMonster object in whole. If you pass the object in then that function can call any and all interfaces on it. It also means that that function has to query the AlienMonster object to see what its capabilities are and then decide which to use. All of this ends up making external a lot of functionality that should be kept internal to class. Because you are externalizing all of that and there is not commonality between IWalk, IRun, ISwim so some function(s) could innocently call all three interfaces and your monster could be running-walking-swimming at the same time. Further since you will want to be able to call IWalk, IRun, ISwim on some classes, all classes will basically have to implement all three interfaces and you'll end up making a strategy like CannotSwim to satisfy the interface requirement for ISwim when a monster can't swim. Otherwise you could end up trying call an interface that isn't implemented on a monster. In the end you are actually making the code worse for the extra interfaces, IMO.
In languages which support multiple inheritance, you could indeed create your Monster by inheriting from classes which represent the things it can do. In these classes, you would write the code for it, so that no code has to be copied between implementing classes.
In C#, being a single inheritance language, I see no other way than by creating interfaces for them. Is there a lot of code shared between the classes, then your IWalkStrategy approach would work nicely to reduce redundant code. In the case of your example, you might also want to combine several related actions (such as walking, swimming and running) into a single class.
Reuse and modularity are Good Things, and having many interfaces with just a few methods is in my opinion not a real problem in this case. Especially because the actions you define with the interfaces are actually different things which may be used differently. For example, a method might want an object which is able to jump, so it must implement that interface. This way, you force this restriction by type at compile time instead of some other way throwing exceptions at run time when it doesn't meet the method's expectations.
So in short: I would do it the same way as you proposed, using an additional I...Strategy approach when it reduces code copied between classes.
From a maintenance standpoint, over-abstraction can be just as bad as rigid, monolithic code. Most abstractions add complication and so you have to decide if the added complexity buys you something valuable. Having a lot of very small work classes may be a sign of this kind of over-abstraction.
With modern refactoring tools, it's usually not too difficult to create additional abstraction where and when you need it, rather than fully architecting a grand design up-front. On projects where I've started very abstractly, I've found that, as I developed the concrete implementation, I would discover cases I hadn't considered and would often find myself trying to contort the implementation to match the pattern, rather than going back and reconsidering the abstraction. When I start more concretely, I identify (more of) the corner cases ahead of time and can better determine where it really makes sense to abstract.
"Find what varies and encapsulate it."
If how a monster walks varies, then encapsulate that variation behind an abstraction. If you need to change how a monster walks, you have probably have a state pattern in your problem. If you need to make sure that the Walk and Growl strategies agree, then you probably have an abstract factory pattern.
In general: no, it is definitely not over-engineering to encapsulate various concepts into their own classes. There is also nothing wrong with making concrete classes sealed or final, either. It forces people to consciously break encapsulation before inheriting from something that probably should not be inherited.

How does this "Programming to Interfaces" thing work?

I like the idea of "programming to interfaces" and avoiding the use of the "new" keyword.
However, what do I do when I have two classes that have the same interface but are fundamentally different to set up. Without going into detail about my specific code, I have an interface with a method, "DoStuff". Two classes implement this interface. One is very simple and requires no initialisation to speak of. The other has five different variables that need to be set up. When combined, they allow for literally millions of ways for the class to work when DoStuff is called.
So when do I "new" these classes? I though about using factories but I don't think they are suitable in this case because of the vast difference in setup. (BTW: there are actually about ten different classes using the interface, each allowing the formation of part of a complex pipeline and each with different configuration requirements).
I think you may be misunderstanding the concept of programming to interfaces. You always have to use the new keyword in object oriented languages to create new instances of objects. Just because you program to interfaces doesn't remove that requirement.
Programming to an interface simply means that all your concrete classes have their behavior defined in an interface instead of in the concrete class itself. So when you define the type of a variable, you define it to be the interface instead of a concrete type.
In your case, just implement DoStuff in your concrete classes as each class needs it implemented (whether doing it simply or with 10 other initialized objects and setup). For example, if you have an interface IInterface and class SomeClass which implements IInterface. You might declare an instance of SomeClass as such:
IInterface myInstance = new SomeClass();
This allows you to pass this instance around to other functions without having to have those functions worry about the implementation details of that instance's class.
Well you really have 3 options. Use new, use a factory or use an DI container. With a DI container your five variables would most likely need to be in a configuration file of some sorts.
But to be completely honest it sounds like you're making your life harder than it needs to be by forcing yourself into a corner. Instead of coding to some ideal, rather code in a manner which best facilitates solving the problem at hand. Not saying you should do a hack job of it, but really, saying you don't want to use new, that is really making your life harder than it needs to be...
Regardless of what you use, at some point you're going to have to construct instances of your classes in order to use them, there's no way around that.
How to go about doing that depends on what you want to accomplish, and the semantics of those classes.
Take the class you mention with those fields.
Can those fields be read from somewhere? A configuration file, as an example? If so, perhaps all you need is just a default constructor that initializes those fields from such a configuration file.
However, if the content of those fields really needs to be passed in from the outside world, there's no way around that.
Perhaps you should look at a IoC container and Dependency Injection?
If you are passing that many configuration parameters into your class it may have too many responsibilities. You should look into breaking it up into smaller classes that only have a single responsibility.
Avoiding the new keyword can be valuable because it creates a dependancy on the implementing class. A better solution would be to use Dependancy Injection.
for example
public interface IDoStuff
{
void DoStuff();
}
public class DoStuffService
{
private IDoStuff doer;
public DoStuffService()
{
//Class is now dependant on DoLotsOfStuff
doer = new DoLotsOfStuff(1,true, "config string");
}
}
public class DoStuffBetterService
{
private IDoStuff doer;
//inject dependancy - no longer dependant on DoLotsOfStuff
public DoStuffBetterService(IDoStuff doer)
{
this.doer = doer;
}
}
Obviously you still have to create the IDoStuff object being passed in somewhere.
An Inversion of Control (IoC) container is a good tool to help with implementing this.
Here is a good tutorial for Castle Windsor Container if you are interested in learning more. (There are many other IoC containers, I just happen to use this one.)
The example in your question was very abstract, so I hope this answer is helpful.
If I understand you correctly the problem is with different initialization. You need to provide for two classes that have the same interface. One does not need anything, and the other needs some paramaters and calls some complex initialization.
You should use have a constructor that gets InitializationParameter. Both classes should get it. One with a simple interface that does not need to get anything from it. The other that needs params and will get them from it.
If you are concerned about initialization you can use factory, just ask it for some interface providing this init parameter and factory will create, init and return to you the object according to the values you provided.
If something is not clear - please ask.

Categories

Resources