Why does factory pattern work the way it does?

血红的双手。 提交于 2019-12-23 17:17:43

问题


I've never really looked at the Factory pattern and today decided to take the time and create a quick sample based on this article (http://msdn.microsoft.com/en-us/library/ee817667.aspx), to finally get my head around it.

The source code works perfectly arranged in three separate assemblies neatly named Product, Factory and Client.

The main benifit (as I understand it) for the Factory pattern is to abstract the instantiation of the "product" class from the "Client" class. So in the provided example, the Product instantiation never changes irrespective of any changes made to the product class, you still have to make changes to the client class to pass zin new values required to create your updated product. This data after all must come from somewhere?

Another example I read stated that once a class is implemented and loads of other classes make use of it directly, changes made to the "product" class here, would require changes to be made to every instantiation of this class, say for example if a new variable was required in its constructor.

From what I can understand, the Factory pattern does make sure the instantiation of this class never changes, if you want to pass a new variable to the products constructor, you simply end up having to pass those new variables to the updated factory instead.

This is therefore clearly not solving the problem but merely moving it and in doing so adds additional complexity.

Given that this is an established pattern, I'm obviously missing something. Hence this post: Please explain to me what I am missing.

Thanks


回答1:


A Factory is used when you can have many distinct implementations of the same interface, and it is only decided runtime which one the client actually needs. However, the client need not know which implementation it is actually using. This is where the Factory steps in: it encapsulates the details of creating a concrete object and returns it as a generic implementation of the required interface.

There are in fact two distinct patterns associated with the name Factory: Abstract Factory and Factory Method. The latter is used to create instances of a single product, while the former is useful to create a whole family of related products.

A typical example of Abstract Factory is the creation of a family of widgets in a GUI framework. Clients of the framework may only need to know that they are dealing with a window, or a status bar, or a button; however, they need not be tied to the fact whether the actual widget is actually a Windows or MacOS widget. This allows one to create clients which can run on either of these platforms; and in theory, when the framework is ported to a new platform, say, Linux, all what is needed is to implement a new factory which produces all the Linux specific widgets, and plug it in via configuration. Lo and behold, the clients run on Linux without noticing any difference, possibly even without the need to recompile the client code (at least in theory,and in some languages - I know that the reality regarding multiplatform GUIs is different, but this is only an example :-)

Compare this to trying to implement the same without factories: you would have many places within the client code where you needed to decide which platform-specific widget you need to create. And whenever you want to introduce a new family of widgets, you would need to modify each of these places within your code to add a new branch to the many identical switch or if/else blocks. Moreover, since you would be openly dealing with platform-specific widget objects, chances are that some platform-specific widget idiosynchrasies and implementation details would leak out into the client code, thus making it even more difficult to port to other platforms.

the Product instantiation never changes irrespective of any changes made to the product class, you still have to make changes to the client class to pass zin new values required to create your updated product. This data after all must come from somewhere?

Indeed. If the general instantiation process changes, the Factory interface may need to change too accordingly. This is not the point of Factory. Although you can pass in data to the factory at its construction time, which it can then use in the background whenever a new Product is created.




回答2:


Using a Factory is a form of Dependency Inversion, a way of decoupling client from implementation.

For example, consider the following:

class Client {
    private DatabaseReader reader = new DatabaseReader();
    public void read() {
        reader.read();
    }
}

Where DatabaseReader is a concrete class. Lets try and break this coupling by defining an interface:

class Client {
    private Reader reader = new DatabaseReader();
    ...
}

Almost there:

class Client {
    private Reader reader = ReaderFactory.getInstance.getReader();
    ...
}

Now, the client does not care if it gets a DatabaseReader, MemoryReader, etc... It becomes the responsibility of the ReaderFactory to provide a suitable Reader.

Dependency injection takes this one step further and does away with the need for loads of Factory classes, instead starting up your code within a dependency injection container.

class Client {
    @Inject 
    private Reader reader;
    ...
}

Where you can have different wiring declared for test / running environments.




回答3:


Here's an excerpt from wikipedia on the factory pattern:

The creation of an object often requires complex processes not appropriate to include within a composing object. The object's creation may lead to a significant duplication of code, may require information not accessible to the composing object, may not provide a sufficient level of abstraction, or may otherwise not be part of the composing object's concerns.

So there's multiple levels of advantages, which in a concrete case may all be present, or just some.

You are correct, that a factory does not solve the problem of having to pass required constructor arguments. However, imagine a case, where these arguments require complex computations to determine (you may need to get values from a database, or something like that). Hence, simply creating an instance of your Product would require some significant portion of code at every place you need to create such an instance.

It is for those complex object instantiations that the factory pattern shines, because your remaining code becomes independent of this complexity involved in the object's creation.

Here's another rough idea to explain it: for a simple object you simply use new MyClass(some_arg). If the instantiation is signifcantly more complex though, you would require several lines of code and possibly additional helper methods. The factory reduces this back to a simple Factory.createMyClass(some_arg).




回答4:


In C++, one does not have virtual constructors. This is still not easy in languages like Java either. This means that one must always know exactly what kind of object on is creating whereven one creates an object. This is a major problem for plugins because it prevents one from abstracting away the object creation code.

The factory pattern solves this problem. One only needs to create the concrete factory once. One can then pass a reference to the abstract factory (from which the concrete factory is derived), in one's generic code and use it whenever one needs to create the concrete object without having to know exactly what object it will be creating.

There are other benefits as well. Since one has only one location from which one creates objects, it is easy to store a list of all created objects.



来源:https://stackoverflow.com/questions/4828435/why-does-factory-pattern-work-the-way-it-does

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!