English 中文(简体)
Is it confusing to call this class a "factory"?
原标题:

My understanding of a factory is that it encapsulates instantiation of concrete classes that all inherit a common abstract class or interface. This allows the client to be decoupled from the process of determining which concrete class to create, which in turn means you can add or remove concrete classes from your program without having to change the client s code. You might have to change the factory, but the factory is "purpose built" and really only has one reason to change--a concrete class has been added/removed.

I have built some classes that do in fact encapsulate object instantiation but for a different reason: the objects are hard to instantiate. For the moment, I m calling these classes "factories", but I m concerned that might be a misnomer and would confuse other programmers who might look at my code. My "factory" classes don t decide which concrete class to instantiate, they guarantee that a series of objects will be instantiated in the correct order and that the right classes will be passed into the right constructors when I call new().

For example, for an MVVM project I m working on, I wrote a class to ensure that my SetupView gets instantiated properly. It looks something like this:

public class SetupViewFactory
{
    public SetupView CreateView(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities)
    {
        var setupViewModel = new SetupViewModel(databaseModel, settingsModel, viewUtilities);
        var setupView = new SetupView();
        setupView.DataContext = setupViewModel;
        return setupView;
    }
}

Is it confusing to call this a "factory"? It doesn t decide among several possible concrete classes, and its return type is not an interface or abstract type, but it does encapsulate object instantiation.

If it s not a "factory", what is it?


Edit

A number of people have suggested that this is actually the Builder Pattern.

The definition of the Builder Pattern from dofactory is as follows:

Separate the construction of a complex object from its representation so that the same construction process can create different representations.

This seems like a little bit of a stretch also. The thing that bothers me is the "different representations". My purpose is not to abstract the process of building a View (not that that isn t a worthy goal). I m simply trying to put the logic for creating a specific view in one place, so that if any of the ingredients or the process for creating that view change, I only have to change this one class. The builder pattern really seems to be saying, "Let s create a general process for making Views, then you can follow that same basic process for any View you create." Nice, but that s just not what I m doing here.


Edit 2

I just found an interesting example in a Wikipedia article on Dependency Injection.

Under "Manually Injected Dependency", it contains the following class:

public class CarFactory {

    public static Car buildCar() {
        return new Car(new SimpleEngine());
    }

}

This is almost exactly the usage I have (and, no, I did not write the wiki article :)).

Interestingly, this is the comment following this code:

In the code above, the factory takes responsibility for assembling the car, and injects the engine into the car. This frees the car from knowing about how to create an engine, though now the CarFactory has to know about the engine s construction. One could create an EngineFactory, but that merely creates dependencies among factories. So the problem remains, but has at least been shifted into factories, or builder objects. [my emphasis]

So, this tells me that at least I m not the only one who s thought of creating a class to help with injecting stuff into another class, and I m not the only one who attempted to name this class a factory.

最佳回答

This doesn t sound much different to me than a constructor for an instance of SetupView. Perhaps too much code context has been elided from your example, but I don t see why what you have right there couldn t simply be written as a constructor, and the arguments passed as args to the constructor.

Judging strictly from GoF patterns, I think it misses the mark on Factory for two reasons:

  1. there is no family of related/dependent objects
  2. the concrete class is, indeed, specified

With regard to Builder, I think it misses in the aspect of variance of products.

When I teach Design Patterns courses, I tell students to look not just at the intent of a pattern when trying to determine "best fit", but rather look at applicability and structure/participants. The intent can help you rule things out, but applicability & structure/participants are what will help you home in.

If you can identify what part of your design fulfills the various roles of the participants in either (Abstract) Factory or Builder, then you ve made a good case for using that nomenclature.

问题回答

It looks to me like what you have there is more of a Builder pattern than a Factory pattern.

I think, it is a "Factory". When I look at the class declaration, I feel happy to see that this is a "Factory", and what s more, it is a "Factory" of SetupView objects. So I know that this Factory will give me concrete and correctly built SetupView instances.

GoF call it "Builder"

A "Factory" is anything that encapsulates the instantiation of new objects. Why, or what the objects are, doesn t matter. The most common use is as you describe, but other purposes that do not fit that description can also be called a Factory. The fundamental idea, (which I don t think any but the most anal or picky developer would misconstrue), is that the thing instantiates new objects for you...

This seems a little weird to me. It s not an abstract factory but it doesn t quite fit the Builder pattern either. What would make the most sense to me is instead of having the SetupViewFactory with the method CreateView, I would move this method to the SetupView class and make it static. So you d have...

public class SetupView
{
    public static SetupView CreateView(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities)
    {
        var setupViewModel = new SetupViewModel(databaseModel, settingsModel, viewUtilities);
        var setupView = new SetupView();
        setupView.DataContext = setupViewModel;
        return setupView;
    }
}

Now you have what is called the static factory or a factory method. You can take it one step further and privatize the SetupView constructors so that the only way to get an instance of SetupView is to call the factory method.

In response to OP s Comment:

If there is such a need for separation I would avoid creating the SetupViewModel anywhere in this part of the code. Instead just pass in the SetupViewModel you want to associate with your SetupView instead of the constituent properties to pass to SetupViewModel s constructor. So the code becomes...

public class SetupView
{
    public static SetupView CreateView(SetupViewModel model)
    {
        var setupView = new SetupView(); { DataContext = model };
        return setupView;
    }
}

Why not two classes with simple constructors?

 public class SetupViewModel {
      public SetupViewModel(DatabaseModel databaseModel, SettingsModel settingsModel, ViewUtilities viewUtilities) {
          this.DatabaseModel = databaseModel;
          this.SettingsModel = settingsModel;
          this.ViewUtilities = viewUtilities;
      }
 }

and

 public class SetupView {         
      public SetupView(SetupViewModel model) {              
          this.DataContext = model;
      }
 }

This way, both classes plainly state what they need to be constructed.

You could call it a "Wizard".

I would tend agree with Jason above. To me it is more like a Builder pattern but if you turned SetupView into an interface it would be more like a Factory pattern. The key to the Factory pattern is letting the Factory pattern do all the work in deciding what to return from the function call. So I would think that you would have to have a switch selecting between various options given the input parameters.





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签