As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
Personally I've never understood the idea of factory classes because it seems a whole lot more useful to just instantiate an Object directly. My question is simple, in what situation is the use of a factory class pattern the best option, for what reason, and what does a good factory class look like?
Here is a real live factory from my code base. It's used to generated a sampler class that knows how to sample data from some dataset (it's originally in C#, so excuse any java faux-pas)
class SamplerFactory
{
private static Hashtable<SamplingType, ISampler> samplers;
static
{
samplers = new Hashtable<SamplingType, ISampler>();
samplers.put(SamplingType.Scalar, new ScalarSampler());
samplers.put(SamplingType.Vector, new VectorSampler());
samplers.put(SamplingType.Array, new ArraySampler());
}
public static ISampler GetSampler(SamplingType samplingType)
{
if (!samplers.containsKey(samplingType))
throw new IllegalArgumentException("Invalid sampling type or sampler not initialized");
return samplers.get(samplingType);
}
}
and here is an example usage:
ISampler sampler = SamplerFactory.GetSampler(SamplingType.Array);
dataSet = sampler.Sample(dataSet);
As you see, it's not much code, and it might even be shorter and faster just to do
ArraySampler sampler = new ArraySampler();
dataSet = sampler.Sample(dataSet);
than to use the factory. So why do I even bother? Well, there are two basic reasons, that build on each other:
First, it is the simplicity and maintainability of the code. Let's say that in the calling code, the enum is provided as a parameter. I.e. if I had a method that need to process the data, including sampling, I can write:
void ProcessData(Object dataSet, SamplingType sampling)
{
//do something with data
ISampler sampler = SamplerFactory.GetSampler(sampling);
dataSet= sampler.Sample(dataSet);
//do something other with data
}
instead of a more cumbersome construct, like this:
void ProcessData(Object dataSet, SamplingType sampling)
{
//do something with data
ISampler sampler;
switch (sampling) {
case SamplingType.Scalar:
sampler= new ScalarSampler();
break;
case SamplingType.Vector:
sampler= new VectorSampler();
break;
case SamplingType.Array:
sampler= new ArraySampler();
break;
default:
throw new IllegalArgumentException("Invalid sampling type");
}
dataSet= sampler.Sample(dataSet);
//do something other with data
}
Note that this monstrosity should be written each and every time I need me some sampling. And you can imagine how fun it will be to change if, let's say, I added a parameter to ScalarSampler constructor, or added a new SamplingType. And this factory has only three options now, imagine a factory with 20 implementations.
Second, it's the decoupling of the code. When I use a factory, the calling code does not know or need to know that a class called ArraySampler even exists. The class could even be resolved at run-time, and the call site would be none the wiser. So, consequently, I am free to change the ArraySampler class as much as I want, including, but not limited to, deleting the class outright, if, e.g. I decide that the ScalarSampler should be used for array data as well. I would just need to change the line
samplers.put(SamplingType.Array, new ArraySampler());
to
samplers.put(SamplingType.Array, new ScalarSampler());
and it would work magically. I do not have to change a single line of code in the calling classes, which could number in the hundreds. Effectively, the factory makes me in control of what and how the sampling occurs, and any sampling changes are efficiently encapsulated within a single factory class that is interfaced with the rest of the system.
The idea here is separation of concerns: If the code that uses the object also has enough information to instantiate it, you don't need a factory. However, if there is some logic or configuration involved that you don't want to have the API user to think about (or mess with), you can hide all that (and encapsulate it for reuse) in a factory.
Here is an example: You want to access one of the services provided by Google App Engine. The same code should work at both the development environment (of which there are two versions, master-slave and high-availabilty) and the completely different local development environment. Google does not want to tell you about the inner workings of their internal infrastructure, and you don't really want to know. So what they do is provide interfaces and factories (and several implementations of those interfaces for the factories to choose from that you don't even need to know about).
Personally, I use the factory pattern when the implementation of an interface is unknown at run time or it can be made dynamic.
This means that as a developer, I work against a known interface to the instance of the object, but I'm not concerned with how the implementation works.
Take, for example. You could use a factory pattern to provide you with objects from a database. You don't care if that database is a flat file, local/single user database, server database or web resource, only that the factory can generate and manage those objects.
I'd hate to have to write implementations for each of those cases :P
From Effective Java book by Joshua Bloch, partially rewritten by me:
1) Static factory methods (SFM), unlike constructors, have names.
public static ComplexNumber one () {
return new ComplexNumber(1, 0);
}
public static ComplexNumber imgOne () {
return new ComplexNumber(0, 1);
}
public static ComplexNumber zero () {
return new ComplexNumber(0, 0);
}
2) It is not required to create a new object each time SFM is/are invoked
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
3) SFM can return an object of any subtype of their return type.
4) SFM reduce the verbosity of creating parameterized type instances.
public static <K, V> HashMap<K, V> newInstance() {
return new HashMap<K, V>();
}
Map<String, List<String>> m = HashMap.newInstance();
To complement Thilo's answer, let us suppose that you have an object which only has a boolean as a constructor: it would be a total waste to build one each time, since it only has two possible values.
In this case, you can create static factory methods. Java's Boolean class is an example: Boolean.valueOf().
You may refer to the wikipedia, but basic idea of most design patterns is to introduce some abstraction to achieve better maintainability and/or reusability. Factory method pattern is no exception, what it does is to abstract away the complexity of creation from the code.
For simple case it seems unnecessary to use factory pattern, a simply new is enough. But when you need more flexibility or functionality, this pattern may help.
For example, unless a new instance is required, the static factory valueOf(boolean) is generally a better choice than new Bealean(boolean), for it avoids creating unnecessary objects. Factory method pattern is also known as Virtual Constructor. As we know, polymorphism is one of the key features of OOP, but constructor cannot be polymorphic, this shortcoming can be overcome by factory method pattern.
In essence, instantiating an object directly(typically via new) is barely a concrete implementation, while factory method pattern shields a volatile implementation by a stable interface(not limited to the interface in Java), pushing the logic of object-creating behind some abstraction to ensure more maintainable and reusable code.
As a final word, to fully understand the benefit of factory method pattern and other design patterns, one need grasp the essence of OOP, including data abstraction, polymorphic abstraction and SOLID principle.
Factory by itself does not show its beauty so easily. Is when you combine it with other patterns when you see the real benefits for example, if you want to use the decorator pattern, instantiating an object directly may add some additional coupling to your code. As the OOP teacher says, coupling is bad :) so if you were to instantiate the decorated object and didn't want to increase coupling then you could use a factory.
Related
When we use Abstract Factory Pattern, we generally have FactoryMaker class which has a getFactory function in which we pass argument and we have switch or if-else logic in the function on the passed parameter to decide which factory to return. Is creating passed parameter an enum or an object and then having the logic of which factory to return inside those object will be better. For example :
Let us say this us our factory maker which are passed enum CountryCode to decide factory.
public class FacoryMaker {
public final static FacoryMaker fctry= new FacoryMaker();
public static RetailFactory getFactory(CountryCode code){
RetailFactory rt = null;
if(code == CountryCode.UK){
rt = new UKFactory();
}
if(code == CountryCode.US){
rt = new USFactory();
}
return rt;
}
}
Instead of this we will have :
public class FacoryMaker {
public final static FacoryMaker fctry= new FacoryMaker();
public static RetailFactory getFactory(CountryCode code){
return code.getFactory();
}
}
and enum will be modified like this:
public enum CountryCode {
US(){
#Override
public RetailFactory getFactory() {
return new USFactory();
}
},
UK(){
#Override
public RetailFactory getFactory() {
return new UKFactory();
}
};
public abstract RetailFactory getFactory();
}
But I don't see this being followed generally. Why is it so? Why can't we make the passing parameter always an object and have the logic inside the object of which factory to get? Can it fail under any abstract factory design. It looks very generic to me. Also by this it is possible to even remove the factory maker and use the object directly to get the Factory instance.
When designing software, one aspect to consider is Separation of Concerns it doesn't sound very reasonable to me to let a CountryCode create a RetailFactory. Both concepts have a pretty low cohesion towards each other, which should be avoided.
Further, if you already have a country code, why would you need a factory at all, what's preventing you to call the getFactory method directly? It simply makes no sense.
The CountryCode is merely a hint for the FactoryMaker's getFactory method, how to create the factory. It may even completely ignore the country code. What if there is a country without a RetailFactory? Do you return null? a DefaultFactory or the Factory of another country?
Of course it is possible to do it that way, but if you look at your code a half year from now, you may think "Wtf? Why the heck did I create the Factory in the Country Code?!"
Besides, the first example you provided seem to be more of a Factory Method than a Factory because the FactoryMaker is not used at all.
I think that Abstract Factory is a general pattern for all OOP languages. When people describe it, they should show a general implementation which is possible to be applied in all of those languages. Then people follow the pattern, they follow genernal implementation.
And your implementation is using Enum which is specifically supported in Java but not other OOP languages.
Very often in practice, factory methods don't know in advance the implementations. The implementing classes may not exist at the time the factory is created. This is the case for example in service provider frameworks such as the Java Database Connectivity API (JDBC). JDBC defines the interfaces that service providers must implement, but the concrete implementations are not known in advance.
This framework allows adding implementations later, for example for database drivers of new cutting edge databases.
The service provider framework includes a provider registration API to register implementations (ex: DriverManager.registerDriver), and a service access API for clients to obtain an instance of the service (ex: DriverManager.getConnection).
It is common to instantiate the service implementation using reflection (ex: Class.forName("org.blah.Driver")).
Your example is different. You know all the implementation classes you intended.
And you are not considering (yet) the pluggability of other implementations.
Whether you create the instances using a switch or an enum,
it makes little difference.
Both alternatives are fine, equivalent.
Another related alternative is that the various methods in Collections do, for example Collections.emptyList(), Collections.singletonList(...), and so on.
The implementations are not decided by a switch,
but have explicit names by way of using specialized methods.
When you want to make it possible to use implementations of your interfaces not known in advance, and not hard-coded in your factory, look into service provider frameworks such as JDBC.
But I don't see this being followed generally. Why is it so?
Your technique only works because you know all the implementations of RetailFactory in advance.
In frameworks like JDBC, all the implementations of Driver, Connection, and so on, are not known in advance, for all the databases out there, so using such technique with a single enum referencing all implementations is not possible, and not scaleable. So they use a different mechanism, to register and load implementations dynamically at runtime.
Why can't we make the passing parameter always an object and have the logic inside the object of which factory to get?
You can. If you don't need dynamic loading of implementations like JDBC (and most probably don't), your way of using enums has some advantages.
For example, your original implementation does rt = ..., which is not as good as doing return .... Such "mistake" is not possible using your enum solution. On the other hand, if you want dynamic loading, then using an enum will not make much sense.
The bottomline is, there is no big difference between the two alternatives you presented. Both are fine.
I am reading the book EMF: Eclipse Modeling Framework where its stated:
The EMF programming model strongly encourages, but doesn’t require,
the use of factories for creating objects. Instead of simply using the
new operator to create [an object]...
Why is the use of factories encouraged over new?
Your answer does not have to be EMF specific, as long as it has to do with Java.
You can read Effective Java Item 1: Consider static factory methods instead of constructors. It describes advantages of using factory methods in detail:
One advantage of static factory methods is that, unlike constructors, they
have names
A second advantage of static factory methods is that, unlike constructors,
they are not required to create a new object each time they’re invoked.
A third advantage of static factory methods is that, unlike constructors,
they can return an object of any subtype of their return type.
A fourth advantage of static factory methods is that they reduce the verbosity of creating parameterized type instances (seems to be outdated since Java 7)
I agree with mostly every answers given here, but those arguments apply generally to every situation in Java, however in this particular case of EMF there is another additional reason: EMF has its own introspection mechanisms, which are used, for instance, for the serialization and deserialization, which doesn't rely in the Java reflection.
For the deserialization, for instance, it reads the XML file, and instantiate the Java objects using the Ecore model information and the respective Factories. Otherwise it would need to use Java reflection.
The answere here is not specific to Java too.
Factory methods have names, it's easier to remember, and less error-prone.
They do not require a new instance to be created each time they are called, you can use preconstructed classes and cache here.
They can return an object of any subtype not only the one called in new
You can parameterize calling "new" object.
The answer to this question is explained in Elegant Objects by Yegor Bugayenko, Chapter 1, Under "1.1 Never use -er names" section.
What the author says is:
A class is a factory of objects.
A class makes objects, though we usually phrase that by saying a class instantiates them:
class Cash {
public Cash(int dollars) {
//...
}
}
Cash five = new Cash(5);
This is different from what we call a Factory Pattern, but only because this "new" operator in Java is not as powerful as it could be. The only thing you can use it for is to make an instance—an object. If we ask class Cash to make a new object, we get a new object. There is no check for whether similar Objects already exist and can be reused, there are no parameters that would modify the behavior of new. etc.
"new" operator is a primitive control for a factory of objects.
Factory Pattern is a more powerful alternative to operator new, but conceptually they are the same. A class is a factory of objects. A class makes objects, keeps track of them, destroys them when necessary, etc.
A Factory Pattern, in Java, works like an extension to the new operator. It makes it more flexible and powerful, by adding an extra logic in front of it.
For example:
class Shapes {
public Shape make(String name) {
if (name.equals("circle")) {
return new Circle();
}
if (name.equals("rectangle")) {
return new Rectangle() ;
}
throw new IllegalArgumentException("not found");
}
}
This is a typical factory in Java that helps us instantiate objects, using textual names of their types. In the end, we still use the new operator. My point is that conceptually, there is not much difference between Factory Pattern and new operator. In a perfect OOP language this functionality would be available in the new operator.
Mainly it is simplicity of creating objects. It's a lot easier to call method from factory than to remember what each parameter in constructor means + it makes changes in code easier
I have a common jar that uses some unmarshaling of a String object. The method should act differently depending on which application it is called from, how can I do that besides from the fact that I can identify the application by trying to load some unique class it has (don't like that). Is there some design pattern that solves this issue?
As I alluded to in my comment, the best thing to do is to break that uber-method up into different methods that encapsulate the specific behaviors, and likely also another method (used by all of the app-specific ones) that deals with the common behaviors.
The most important thing to remember is that behavior matters. If something is behaving differently in different scenarios, a calling application effectively cannot use that method because it doesn't have any control over what happens.
If you still really want to have a single method that all of your applications call that behaves differently in each one, you can do it, using a certain design pattern, in a way that makes sense and is maintainable. The pattern is called "Template Method".
The general idea of it is that the calling application passes in a chunk of logic that the called method wraps around and calls when it needs to. This is very similar to functional programming or programming using closures, where you are passing around chunks of logic as if it were data. While Java proper doesn't support closures, other JVM-based languages like Groovy, Scala, Clojure, JRuby, etc. do support closures.
This same general idea is very powerful in certain circumstances, and may apply in your case, but such a question requires very intimate knowledge of the application domain and architecture and there really isn't enough information in your posted question do dig too much deeper.
Actually, I think a good OO oriented solution is, in the common jar, to have one base class, and several derived classes. The base class would contain the common logic for the method being called, and each derived class would contain specific behavior.
So, in your jar, you might have the following:
public abstact class JarClass {
public method jarMethod() {
//common code here
}
}
public class JarClassVersion1 extends JarClass {
public method jarMethod() {
// initiailzation code specific to JarClassVerion1
super.jarMethod();
// wrapup code specific to JarClassVerion1
}
}
public class JarClassVersion2 extends JarClass {
public method jarMethod() {
// initiailzation code specific to JarClassVerion2
super.jarMethod();
// wrapup code specific to JarClassVerion2
}
}
As to how the caller works, if you are willing to design your code so that the knowledge of which derived class to use resides with the caller, then you obviously just have the caller create the appropriate derived class and call jarMethod.
However, I take it from your question, you want the knowledge of which class to use to reside in the jar. In that case, there are several solutions. But a fairly easy one is to define a factory method inside the jar which creates the appropriate derived class. So, inside the abstract JarClass, you might define the following method:
public static JarClass createJarClass(Class callerClass) {
if (callerClass.equals(CallerClassType1.class)) {
return new JarClassVersion1();
} else if (callerClass.equals(CallerClassType2.class)) {
return new JarClassVersion1();
// etc. for all derived classess
}
And then the caller would simply do the following:
JarClass.createJarClass(this.getClass()).jarMethod();
I'm familiar with the idea and benefits of a static factory method, as described in Joshua Bloch's Effective Java:
Factory methods have names, so you can have more than one factory method with the same signature, unlike constructors.
Factory methods don't have to create a new object; they can return a previously-created object. This is good for immutable objects or value objects.
Factory methods can return an object of any subtype of their return type, unlike constructors.
Now I'm trying to explain static factory methods for someone who is learning Java and OO principles. She learns best from concrete scenarios instead of abstractions. If she can see the pattern at work, solving some problem, she'll get it. But she finds it harder to read an abstract list of characteristics like the above to understand how to apply the pattern.
Can you help me come up with a realistic example of using a static factory method, that makes its benefits clear, but which is still simple enough to show someone in an introductory Java class?
This person does have programming experience in PL/SQL but never got around to learning OOP patterns.
Use javax.swing.BorderFactory as an example of all three points.
This class is used to make borders for swing objects. These border objects can be easily re-used, and this factory method allows for this. Here is the javadoc. This factory is a great example of all three points:
There are multiple static methods with different names like createEmptyBorder() and createEtchedBorder().
These methods will return previously created objects when possible. It's quite frequent that the same border would be used throughout an application.
Border itself is actually an interface, so all objects created through this factory are actually classes which implement this interface.
The textbook example of your second point is Integer.valueOf(int) (similar for Boolean, Short, Long, Byte). For parameter values -128 to 127, this method returns a cached instance instead of creating a new Integer. This makes (auto)boxing/unboxing much more performant for typical values.
You can't do that with new Integer() since the JLS requires that new create a new instance every time it is called.
My current favorite example of this pattern is Guava's ImmutableList. Instances of it can only be created by static factories or a builder. Here are some ways that this is advantageous:
Since ImmutableList doesn't expose any public or protected constructors, it can be subclassed within the package while not allowing users to subclass it (and potentially break its immutability guarantee).
Given that, its factory methods are all able to return specialized subclasses of it without exposing their types.
Its ImmutableList.of() factory method returns a singleton instance of EmptyImmutableList. This demonstrates how a static factory method doesn't need to create a new instance if it doesn't have to.
Its ImmutableList.of(E) method returns an instance of SingletonImmutableList which is optimized because it will only ever hold exactly 1 element.
Most of its other factory methods return a RegularImmutableList.
Its copyOf(Collection) static factory method also does not always need to create a new instance... if the Collection it is given is itself an ImmutableList, it can just return that!
Wouldn't Calendar.getInstance() be a good exmaple?
It creates depending on the locale a BuddhistCalendar, JapaneseImperialCalendar or by default a GregorianCalendar.
Here is one I had to do a while back. At a job interview, I was asked to program a deck of cards where they can be shuffled. Really simple problem. I created:
Card:
suit
rank
Deck:
card[]
I think what was the distinguishing factor is that there can only 52 cards at all times. So I made the constructor for Card() private and instead create static factory valueOf(suit, rank) This allowed me to cache the 52 cards and make the immutable. It taught many important basic lessons in that books.
immutable
control creation of object
static methods
possibly subclassing and return a card from another source. ( I didn't do this)
This is similar to Boolean and Byte, except I used a common homework example to show why its important to control the instances. I also created a helper function for deck called newDeck() because I wanted to show an instance where the constructor might not need to be private but it would still be nice to have a helper static factory.
I hope this helps!
The simple case. Suppose you have a class which operates some sort of printer, but it doesn't care if it is epson, canon or something else. So, you just create an Interface Printer, create some implementations of it and create a class which has only one method: createPrinter.
So, the code will be simple:
public interface Printer {
print();
}
class CanonPrinter implements Printer {
print() {
// ...
}
}
public PrinterFactory {
Printer createPrinter() {
if (... ) {
return new CanonPrinter();
} else {
return new EpsonPrinter();
}
}
}
client code:
Printer printer = PrinterFactory.createPrinter();
printer.print();
Here you abstract you clinet code from any details of what printers you can operate with or how they manage printing. It's PrinterFactory who cares what printer to choose if one for example malfunctions.
I have a pipeline-based application that analyzes text in different languages (say, English and Chinese). My goal is to have a system that can work in both languages, in a transparent way. NOTE: This question is long because it has many simple code snippets.
The pipeline is composed of three components (let's call them A, B, and C), and I've created them in the following way so that the components are not tightly coupled:
public class Pipeline {
private A componentA;
private B componentB;
private C componentC;
// I really just need the language attribute of Locale,
// but I use it because it's useful to load language specific ResourceBundles.
public Pipeline(Locale locale) {
componentA = new A();
componentB = new B();
componentC = new C();
}
public Output runPipeline(Input) {
Language lang = LanguageIdentifier.identify(Input);
//
ResultOfA resultA = componentA.doSomething(Input);
ResultOfB resultB = componentB.doSomethingElse(resultA); // uses result of A
return componentC.doFinal(resultA, resultB); // uses result of A and B
}
}
Now, every component of the pipeline has something inside which is language specific. For example, in order to analyze Chinese text, I need one lib, and for analyzing English text, I need another different lib.
Moreover, some tasks can be done in one language and cannot be done in the other. One solution to this problem is to make every pipeline component abstract (to implement some common methods), and then have a concrete language-specific implementation. Exemplifying with component A, I'd have the following:
public abstract class A {
private CommonClass x; // common to all languages
private AnotherCommonClass y; // common to all languages
abstract SomeTemporaryResult getTemp(input); // language specific
abstract AnotherTemporaryResult getAnotherTemp(input); // language specific
public ResultOfA doSomething(input) {
// template method
SomeTemporaryResult t = getTemp(input); // language specific
AnotherTemporaryResult tt = getAnotherTemp(input); // language specific
return ResultOfA(t, tt, x.get(), y.get());
}
}
public class EnglishA extends A {
private EnglishSpecificClass something;
// implementation of the abstract methods ...
}
In addition, since each pipeline component is very heavy and I need to reuse them, I thought of creating a factory that caches up the component for further use, using a map that uses the language as the key, like so (the other components would work in the same manner):
public Enum AFactory {
SINGLETON;
private Map<String, A> cache; // this map will only have one or two keys, is there anything more efficient that I can use, instead of HashMap?
public A getA(Locale locale) {
// lookup by locale.language, and insert if it doesn't exist, et cetera
return cache.get(locale.getLanguage());
}
}
So, my question is: What do you think of this design? How can it be improved? I need the "transparency" because the language can be changed dynamically, based on the text that it's being analyzed. As you can see from the runPipeline method, I first identify the language of the Input, and then, based on this, I need to change the pipeline components to the identified language. So, instead of invoking the components directly, maybe I should get them from the factory, like so:
public Output runPipeline(Input) {
Language lang = LanguageIdentifier.identify(Input);
ResultOfA resultA = AFactory.getA(lang).doSomething(Input);
ResultOfB resultB = BFactory.getB(lang).doSomethingElse(resultA);
return CFactory.getC(lang).doFinal(resultA, resultB);
}
Thank you for reading this far. I very much appreciate every suggestion that you can make on this question.
The factory idea is good, as is the idea, if feasible, to encapsulate the A, B, & C components into single classes for each language. One thing that I would urge you to consider is to use Interface inheritance instead of Class inheritance. You could then incorporate an engine that would do the runPipeline process for you. This is similar to the Builder/Director pattern. The steps in this process would be as follows:
get input
use factory method to get correct interface (english/chinese)
pass interface into your engine
runPipeline and get result
On the extends vs implements topic, Allen Holub goes a bit over the top to explain the preference for Interfaces.
Follow up to you comments:
My interpretation of the application of the Builder pattern here would be that you have a Factory that would return a PipelineBuilder. The PipelineBuilder in my design is one that encompases A, B, & C, but you could have separate builders for each if you like. This builder then is given to your PipelineEngine which uses the Builder to generate your results.
As this makes use of a Factory to provide the Builders, your idea above for a Factory remains in tact, replete with its caching mechanism.
With regard to your choice of abstract extension, you do have the choice of giving your PipelineEngine ownership of the heavy objects. However, if you do go the abstract way, note that the shared fields that you have declared are private and therefore would not be available to your subclasses.
I like the basic design. If the classes are simple enough, I might consider consolidating the A/B/C factories into a single class, as it seems there could be some sharing in behavior at that level. I'm assuming that these are really more complex than they appear, though, and that's why that is undesirable.
The basic approach of using Factories to reduce coupling between components is sound, imo.
If I'm not mistaken, What you are calling a factory is actually a very nice form of dependency injection. You are selecting an object instance that is best able to meet the needs of your parameters and return it.
If I'm right about that, you might want to look into DI platforms. They do what you did (which is pretty simple, right?) then they add a few more abilities that you may not need now but you may find would help you later.
I'm just suggesting you look at what problems are solved now. DI is so easy to do yourself that you hardly need any other tools, but they might have found situations you haven't considered yet. Google finds many great looking links right off the bat.
From what I've seen of DI, it's likely that you'll want to move the entire creation of your "Pipe" into the factory, having it do the linking for you and just handing you what you need to solve a specific problem, but now I'm really reaching--my knowledge of DI is just a little better than my knowledge of your code (in other words, I'm pulling most of this out of my butt).