Constructor vs. Factory in .NET Framework

邮差的信 提交于 2019-12-02 05:36:31

问题


Below is an article about .net framework's use of patterns. I'm not sure I understand the bolded part in the excerpt below. Is it implying if you change the details of creating the object, you (might) change the constructor arguments?

There are many cases in the Framework where you can obtain a new instance of a struct or class without calling its constructor yourself. The System.Convert class contains a host of static methods that work like this. To convert an integer to a Boolean, for example, you can call Convert.ToBoolean and pass in the integer. The return value of this method call is a new Boolean set to "true" if the integer was non-zero and "false" otherwise. The Convert class creates the Boolean for you with the correct value. Other type conversion methods work similarly. The Parse methods on Int32 and Double return new instances of those objects set to the appropriate value given only a string.

This strategy for creating new object instances is known as a Factory pattern. Rather than invoking the object's constructor, you can ask the object factory to create the instance for you. That way, the factory class can hide the complexity of object creation (like how to parse a Double out of a string). If you wanted to change the details of creating the object, you'd only have to change the factory itself; you would not have to change every single place in the code where the constructor is called.

From: http://msdn.microsoft.com/en-us/magazine/cc188707.aspx.


回答1:


I actually think that the examples they've provided are not necessarily great examples.

The Factory pattern becomes more useful in .NET when you're constructing classes. For example, look at the WebRequest class.

This class is normally instantiated by calling:

WebRequest request = WebRequest.Create(url);

The WebRequest.Create method uses the Factory pattern. Depending on the type of URL, it will create a different type (subclass) of WebRequest. If you pass it an http:// url, for example, you will actually create an HttpWebRequest instance - an ftp:// URL will create an FtpWebRequest.

By using the Factory pattern here, more URL types can be added later without changing any code on the client side - you just pass in the different URL (as a string), and get a new object.




回答2:


The whole idea of factory seems different. It's not just about hiding the complexity of implementation, it's about inversion of control as well (IoC).

  • Instead of creating Sender and Receiver objects your own, let's make MessageFactory object responsible for creating them.
  • Let's imagine initially we implemented a TcpMessageFactory (MessageFactory descendant) creating TcpSender and TcpReceiver objects. So now our application works with TCP.
  • A bit later we discovered that UDP is faster. So we implemented UdpSender and UdpReciever. Moreover, we implemented UdpMessageFactory (MessageFactory descendant as well)
  • Now we can allow user to choose which protocol to use. Based on this, we create our factory object (either TcpMessageFactory or UdpMessageFactory) and use it in our application further.

In this example MessageFactory.CreateSender and MessageFactory.CreateReciever must be abstract methods; methods of Sender & Reciever forming their public API (contract) must be abstract as well.

Btw, initially factories were used mainly for object creation: imagine C++ library (DLL) that must allow to create a set of its own types to the main .exe. Passing the instances between different modules there is almost impossible, because their structure depends on a particular compiler. But it's possible to pass the interfaces. So such DLL should:

  • Export a function returning factory interface, e.g. IDllTypeFactory
  • The object implementing it must return IDllTypeXxx objects on invocation of its CreateXxx methods. These IDllTypeXxx are actually implemented by the types we originally planned to export.

But as you know, .NET with its unified assembly format makes it possible to pass the objects between different modules. Moreover, reflection allows to create a type you don't know at all. So factories in .NET are used more rarely.




回答3:


The Factory Pattern is the one that I use the most on my programs. It can be very helpful on certain cases, but you should certainly be careful when using it. If your factory looks like a constructor overload, then it probably should be a constructor overload. The examples that were given by the MSDN article aren't good. In fact, it has been my belief for quite some time that objects like Int, String, etc., don't contemplate overloads for each other because they are structs rather than classes and, as a rule, struct constructors should not throw exceptions (which would happen if, for example, you could feed a "hello world" to a int). But I assumed that.

There are, of course, lots of place around the web where you can find better explanations of when to use the factory pattern and its benefits. The example given by Reed is one of the best and follows my rule for using Factories: I use factories when I have a class hierarchy or a number of classes that implement a certain interface and I want to build one of those objects but receive an object of the superclass/interface rather than the object itself. That way, the object that's calling the factory doesn't have to worry about implementation details. It knows that it's expecting an object of a certain class, and that's what it gets, even if it's a cast.

In the current application I'm building (a program generator), I need to parse a datatable SQL definition. I use a home-brew parser to do that. Each time the parser encounters a variable ("IDENTIFIER VARIABLE-TYPE"), I call a factory and pass the string to it. The factory then checks the variable-type substring and returns to me a SqlVariable, that could actually be an IntegerSqlVariable or a CharSqlVariable.

The main parser object doesn't know what variable it got. It pushes the SqlVariable to a list and reads the next line. Of course, I could have a single class to deal with all variable types; I personally choose not to do so.




回答4:


Yes, you could use constructor overloads to change the constructor without having to alter every area in the source code but that will quickly lead to a ridiculous number of constructors if you aren't very careful.

I think the general idea of the article is hiding the implementation rather than necessarily preventing massive constructor overloads in order to account for constructor changes. The idea being the object shouldn't have knowledge of how it can be constructed.

In the example given, you don't want to clog your Int class with how it could become an int from a string or a double so you create your Factory whose sole responsibility is to create X object from Y parameters.

I would definitely suggest the Head First Design Patterns book as a good intro to learning Design Patterns. The examples are Java based but the logic behind them applies no matter what language you are using.



来源:https://stackoverflow.com/questions/1869519/constructor-vs-factory-in-net-framework

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