My application stores files, and you have the option of storing the files on your own server or using S3.
I defined an interface:
interface FileStorage {
}
Then I have 2 implementations, S3FileStorage and LocalFileStorage.
In the control panel, the administrator chooses which FileStorage method they want, and this value is stored in a SiteConfiguration object.
Since the FileStorage setting can be changed while the application is already running, would you still use spring's DI to do this?
Or would you just do this in your code:
FileStorage fs = null;
switch(siteConfig.FileStorageMethod)
case FileStorageMethod.S3:
fs = new S3FileStorage();
case FileStorageMethod.Local:
fs = new LocalFileStorage();
Which one makes more sense?
I believe you can use DI with spring during runtime, but I haven't read about it much at this point.
I would inject a factory, and let clients request the actual services from it at runtime. This will decouple your clients from the actual factory implementation, so you can have several factory implementations as well, for example, for testing.
You can also use some kind of a proxy object with several strategies behind it instead of the factory, but it can cause problems, if sequence of calls (like open, write, close for file storage) from one client cannot be served by different implementations.
I would still use Dependency Injection here. If it can be changed at runtime, you should inject it using setter injection, rather than constructor injection. The benefit of using any dependency injection is that you can easily add new implementations of the interface without changing the actual code.
DI without question. Or would you prefer to enhance your factory code when you create/update/delete an implementation? IMO, If you're programming to an interface, then you shouldn't bootstrap your implementations, however many layers deep it actually occurs.
Also, DI isn't synonymous to Spring, et al. It's as simple as containing a constructor with the abstracted interface as an argument, i.e. public FileApp(FileStorage fs) { }.
FYI, another possibility is a proxy.
Related
There's a nice tutorial that seems to make sense about DI and IoC
Wouldn't it be easier to make the getCustomer methods static in the injector classes? I don't really see any reason to instantiate injector objects in this case.
So instead of:
MessageServiceInjector injector = null;
Consumer app = null;
injector = new EmailServiceInjector();
app = injector.getConsumer();
app.processMessages(msg, email);
We would just do:
Consumer app = null;
app = EmailServiceInjector.getConsumer();
app.processMessages(msg, email);
How to write injector classes properly? At the end of the article it says
We can achieve IoC through Factory Pattern, Template Method Design
Pattern, Strategy Pattern and Service Locator pattern too
but I guess none of the patterns was used in this example (IoC in this case is just simplistic). So how would it be done in a real project (assuming no external frameworks or IoC containers are used), i.e. if I wanted to create all the necessary stuff to let me use DI in my code.
"Easier"? I don't think it makes any difference to your DI engine.
Static would assume one instance. What if you want an instance per request, as you might for each web request? Static won't do then.
I've used Spring for more than ten years. It has a bean factory and DI capability that can deal with singleton or per request instances. Have a look at how it works to see one successful way to do it.
I think Martin Fowler's DI article, now 11 years old, still explains it well.
In real world project, you should use Dependency injection framework like Spring Framework. The are other as well likeGoogle Guice.
I have been personally using spring for couple of years now and it has grow to much larger extent apart from basic DI.
Wouldn't it be easier to make the getCustomer methods static in the injector classes?
It seems to me that what this article is calling an Injector is actually an abstract factory. We use abstract factories when we want a class to create objects at a later point it time.
In general it is not recommended to have static methods. Mainly because the classes that call the static method will have a hard dependency on it, i.e., you cannot at a later point in time consume a different dependency without changing the consuming class code. And this is exactly the problem that DI is trying to solve.
Another reason is that it is hard to mock static methods in a unit test.
So how would it be done in a real project?
In real projects you should construct your objects (e.g. services) in the composition root.
There are two ways to do it. Either use a DI container, or use Pure DI.
In my opinion, Pure DI is a better choice. See this article for a reason why.
In C++ or C, you can do things like this:
#ifdef WINAPI
public void showWindow(int cmdShow);
#endif
But in java, how can I define methods, that will only be compiled when user has enabled a library? I'm making a cross-platform application that uses certain native features which were not yet abstracted by JVM.
Also, I often make constructors that allow making my class from an object coming from some library. In that case, once the constructor is there, it force user to have that library. Instead, I'd like it to be only enabled when user has that library.
Java does not have the concept of macros or templates. Instead it has reflection and generics. In your case, you would use reflection. The idea is to code to interfaces and then at runtime figure out which implementation to use. If no suitable/custom implementation is found you need to fall back to some default (possibly a no-op implementation if you want nothing to happen by default).
The best way to support such architecture is to provide an entry point to your hierarchy of interfaces, i.e., a factory. The entry point will then provide to all clients the implementations they need. The entry point can use reflection to figure out which implementation you want, e.g.,
public final class LibraryManager {
public static LibraryInterface find(String url) { ... }
}
The LibraryManager above figures out via reflection which implementation of LibraryInterface you want to obtain at runtime. The url can be simply the fully qualified class name of the required implementation of LibraryInterface, e.g., com.my.pack.MyLibraryInterfaceImpl.
To understand this in practice, take a look at JDBC's DriverManager: you get an implementation of Connection by providing the DriverManager.getConnection method with a jdbc URL. Behind the curtains, DriverManager uses reflection to find the right driver and returns the implementation needed. If the driver library for the given URL is not available you will get an exception.
In your case, the only modification you need to make to that pattern is to provide some default implementation if no library is specified. If the implementations rely on 3rd party libraries you are going to need to write appropriate adapters that use these, etc.
Note that in many cases you would actually return a factory to your library implementation so you can create many instances of the library objects. This works exactly the same way as above except you return some LibraryFactoryInterface instead.
Finally, if you use some kind of IoC or DI framework like Spring, you can define your implementation factory at configuration time to be injected in your application. A typical example and an alternative to DriverManager is DataSource. It's very common in a Spring application to define your DataSources in the configuration file. Spring will take care of wiring the DataSource into the objects that need to connect to the database.
What's wrong with following code?
public class DeDoper {
public boolean wackapediaOkToday() {
DnsResolver resolver = ResolverFactory.getInstance().makeResolver();
return resolver.getIpAddressFor("wackapedia.org").equals("123.456.78.9");
}
}
Why is this version preferred?
public class DeDoper {
#InjectService
private DnsResolver resolver;
public boolean wackapediaOkToday() {
return resolver.getIpAddressFor("wackapedia.org").equals("123.456.78.9");
}
}
I can easily mock ResolverFactory.makeResolver() and this is the same as setting resolver is latest example.
This is what was said in this article from ProQuest.biz:
This [first] version of WackapediaOkToday is, very loosely speaking, "injected" with a DnsResolver (although it's admittedly less like getting a shot, and more like asking a waiter for the check). But it does solve the testing problem, and the "turtles all the way down" problem.
Chained to the Factory
But in this [first version] approach, we are literally "chained" to the Factory classes. (Worse, if the objects created by our Factories have dependencies in turn, we may have to introduce new Factories inside our Factories.) We haven't fully "inverted" our control, we're still calling (controlling) the Factories from inside our classes.
What was needed was a way to get rid of the control in our classes entirely, and have them told what they were getting (for their dependencies).
Let's say you had a service which can have multiple implementations, like "FileLocator". This has a FilesystemFileLocator, which takes as an argument the path to the root of the files and a S3FileLocator, which takes as an argument your S3 credentials. The former would require you to write a service locator to figure out which version you want and then return it. That code, in turn, has to go get your data, build the appropriate type of file locator, etc. You're doing what the IOC container should do for you. On top of that, you've inject a dependency on that specific creation method.
In the second version you've defined (through annotations or XML) what type of file locator you want. The IOC container instantiates and manages that for you. It's less code you have to maintain. It's also less work if you want to introduce a third type of FileLocator. Or maybe you refactor your code so file locators are singletons, or if they were singletons they're now factories for fresh locators, or maybe you want to pool locator instances. In all these cases there will be less breakage if you work with your IOC container.
Maybe i missed it in the documentation but i'm wondering how i should handle "helper Objects"?
code example:
public Path dijkstra(Node startNode, Node endNode) {
Set<Node> nodesToInspect = new HashSet<Node>(); // should this Object be injected?
Path path = new Path(); // and this one?
while (!nodesToInspect.isEmpty()) {
// some logic like:
path.add(currentNode);
}
return path;
}
Should i inject everything or should i say at some point that the algorithm "knows" best what it needs?
Should i try to eliminate every "new"? or are some object creations fine, for example API classes like HashSet, ArrayList, etc.
Before you replace a simple new with dependency injection, you need to ask yourself "why am I doing this?" ... "what real benefit does it have?". If the answer is "I don't know" or "nothing", then you shouldn't.
In this case, I can see no real benefit in using DI in the first cases in your example code. There is no need for anything outside of that method to know about how the internal set is represented ... or even to know that it exists.
The other question you should ask is whether there is a simpler, more obvious way of achieving the goal. For example, the (most likely) purpose of using DI for the path variable is to allow the application to use a different Path class. But the simple way to do that is to pass a Path instance to the dijkstra method as an explicit parameter. You could even use overloading to make this more palatable; e.g.
public Path dijkstra(Node startNode, Node endNode) {
return dijkstra(startNode, endNode, new Path());
}
public Path dijkstra(Node startNode, Node endNode, Path path) {
...
}
The final thing to consider is that DI (in Java) involves reflection at some level, and is inevitably more expensive than the classical approaches of using new or factory objects / methods. If you don't need the extra flexibility of DI, you shouldn't pay for it.
I just noticed that the two variables you are referring to are local variables. I'm not aware of any DI framework that allows you to inject local variables ...
Remember the design principle: "Encapsulate what changes often" or "encapsulate what varies". As the engineer, you know best what is likely to change. You wouldn't want to hard-code the year 2012 into code that will live until next decade, but you also wouldn't want to make "Math.PI" a configuration setting either--that'd be extra overhead and configuration that you'd never need to touch.
That principle doesn't change with dependency injection.
Are you writing one algorithm and you know which implementation of Set you need, like in your Dijkstra example? Create your object yourself. But what if your co-worker is soon to deliver a fantastic new implementation of Set optimized for your use-case, or what if you are experimenting with different collection implementations for benchmarking? Maybe you'll want to inject a Provider until the dust settles. That's less likely for collections, but maybe it's more likely for similar disposable objects you might think of as "helper objects".
Suppose you're choosing between different types of CreditCardAuthService that may vary at runtime. Great case for injection. But what if you've signed a five-year contract and you know your code is going to be replaced long before then? Maybe hard-coding to one service makes more sense. But then you have to write some unit tests or integration tests and you really don't want to use a real credit card backend. Back to dependency injection.
Remember: code is malleable. Someday you may decide that you need to rip out your hard-coded HashSet and replace it with something else, which is fine. Or maybe you'll discover that you need your service to vary often enough that it should be Guice-controlled, and then you add a constructor parameter and a binding and call it a day. Don't worry about it too much. Just keep in mind that just because you have a hammer, not every problem is a Provider<WoodFasteningService>.
When working with DI, I prefer to avoid "new" whenever possible. Every instance you create outside the container (e.g. the guice injector) can not refactored to use injection (what if your "Path" instance should get a String "root" injected by configuration ... and you cannot use interceptors on those objects either.
So unless it is a pure Entity-Pojo, I use Provides/Inject all the time.
It's also part of the inversion of control (hollywood) pattern and testability ... what if you need to mock Path or Set in Junit? if you have them injected (in this case the Providers), you can easily switch concrete implementation afterwards.
I want to design the file storage part of my application with some flexibility, so one can store files in either S3 or on the web server's hard drive.
I also want this to be flexible on a per user basis, so in their user settings they can choose if they want their files stored in S3 or on the servers file system.
I am thinking of something like this:
IFileStorage fs = FileStorageFactory.Instance(userSettings);
Then I would have a method that looks like:
public static IFileStorage Instance(UserSettings setting)
{
if(setting == UserSettings.S3)
return new S3FileStorage();
}
Does this make sense? (I'm a c# programmer but I will be doing this in Java)
I am using Spring, but I don't think DI will be used here since the implementation changes on a per user basis.
Factory and Dependency Injection aren't mutually exclusive. Spring has the so-called factory-method which produces beans. You can pass arguments to the factory-method, and it can be either static or non-static.
Yes. That seems appropriate. You're returning a particular instance of a class to the user, so as long as their requirements don't change halfway through the program, then the factory is appropriate (otherwise I'd recommend a strategy pattern)