I am developing a kind a translator from language A to B (yeah, it kinda is like a compiler). A translation is generally from several different files and each one of them has the same 3 sections to trans开发者_高级运维late. So, the way I did it, I kind of have it the following way:
When I instantiate a translator and give it some data, it will need to generate all the needed FileTranslator classes. As I shouldn't do the new
in Translator, I should ask for a factory from above. The same happens in the Sections translators. This poses the problem that I'm forced to create a lot of boilerplate factories. Moreover, each one of the translators might need even more factories to generate some other classes they might want to use.
Am I thinking this the wrong way or is it just the way it is? I am not allowed to use any kind of DI/IoC framework in this project, btw.
Edit:
I'm afraid I am not getting my message get sent across.
In this specific case, as my Translator class needs to be able to generate at any moment some FileTranslator, it would need a FileTranslatorFactory. I know I can have an IoC Container do the wiring for me, but the IoC Container in itself will not save me for the problem of having to code up the code of the FileTranslatorFactory itself. Am I right?
Now, the problem is that a FileTranslator will also have to be able to generate whenever it needs SectionATranslators, SectionBTranslators and SectionCTranslators (and do not think they are any similar because their names are -- they are totally different and have nothing to do with each other!). So I'd have to define factories for each one of them. So for such a simple 5 classes system, I'd need to create 4 (!!!) factories.
Being that I don't want my domain objects to depend on an IoC-Container and that I don't want to have a single factory for all the 4 kinds of objects that seem to need one, am I still missing something?
The fact that there is a lot of boilerplate code involved in handcranking DI for class hierarchies like this is WHY the frameworks exist. Sorry, but unless you can get whoever decided on the no DI/IoC frameworks rule to change their mind, you are either going to be writing lots of boilerplate code, or you will end up writing a framework yourself.
EDIT - with a completely fictitious framework, to keep this as agnostic as possible, but explaining how you can eliminate all but one call into the container in many scenarios.
So, with an implementation of Translator
like:
public class Translator
{
private ITranslator translatorInstance;
public Translator()
{
SomeContainer container = SomeContainer.CreateFromConfig(configFilePath);
// this is the ONLY point we touch the container
translatorInstance = container.GetMeA<ITranslator>();
}
// implementation
}
We can see that this works as a factory, and is the only class that needs to know about the container itself. An implementation of one concrete implementor of ITranslator
could therefore be:
public class FileTranslator : ITranslator
{
// private fields
public FileTranslator( ISectionATranslator sectionAtrans,
ISectionBTranslator sectionBtrans,
ISectionCTranslator sectionCtrans)
{
this.sectionAtrans = sectionAtrans;
// etc
}
// implementation
}
Note here that FileTranslator
knows nothing about which concrete classes actually implement the interfaces it depends on, nor does it need any sort of factory. In fact, the container will do this for you. There are several ways containers work this stuff out, one example is explicit config, something like:
<!-- absolutely fictitious configuration file, but similar to many frameworks -->
<ContainerConfig>
<ObjectResolver interface="ITranslator">
<ConcreteType type="FileTranslator">
<ConstructorInjection>
<Argument ordinal="0" type="SectionATranslator" />
<Argument ordinal="1" type="SectionBTranslator" />
<Argument ordinal="2" type="SectionCTranslator" />
</ConstructorInjection>
</ConcreteType>
</ObjectResolver>
</ContainerConfig>
Many frameworks don't even need you to define the specific constructor arguments, you can just state that if you want a ISectionATranslator
then return a SectionATranslator
and it will automatically create these before calling the constructor.
Also note that some frameworks provide the option to define these type resolution rules in code, using fluent style APIs, and some allow you to define multiple potential ways of resolving a particular type, via some name (perhaps a "Production"
implementation versus a "UnitTest"
implementation).
Note that I have kept the above deliberately vague because I don't want to say which framework is best (and to be honest, I think it depends on your individual needs) - check elsewhere on StackOverflow for framework comparisons, and please try a few out (perhaps you can try some without telling your boss!). Hopefully, however, the above shows why an IoC container can make your code much cleaner by removing the need for layers upon layers of factory classes.
精彩评论