Factory pattern in C#: How to ensure an object instance can only be created by a factory class?

53,122

Solution 1

Looks like you just want to run some business logic before creating the object - so why dont you just create a static method inside the "BusinessClass" that does all the dirty "myProperty" checking work, and make the constructor private?

public BusinessClass
{
    public string MyProperty { get; private set; }

    private BusinessClass()
    {
    }

    private BusinessClass(string myProperty)
    {
        MyProperty = myProperty;
    }

    public static BusinessClass CreateObject(string myProperty)
    {
        // Perform some check on myProperty

        if (/* all ok */)
            return new BusinessClass(myProperty);

        return null;
    }
}

Calling it would be pretty straightforward:

BusinessClass objBusiness = BusinessClass.CreateObject(someProperty);

Solution 2

You can make the constructor private, and the factory a nested type:

public class BusinessObject
{
    private BusinessObject(string property)
    {
    }

    public class Factory
    {
        public static BusinessObject CreateBusinessObject(string property)
        {
            return new BusinessObject(property);
        }
    }
}

This works because nested types have access to the private members of their enclosing types. I know it's a bit restrictive, but hopefully it'll help...

Solution 3

Or, if you want to go really fancy, invert control: Have the class return the factory, and instrument the factory with a delegate that can create the class.

public class BusinessObject
{
  public static BusinessObjectFactory GetFactory()
  {
    return new BusinessObjectFactory (p => new BusinessObject (p));
  }

  private BusinessObject(string property)
  {
  }
}

public class BusinessObjectFactory
{
  private Func<string, BusinessObject> _ctorCaller;

  public BusinessObjectFactory (Func<string, BusinessObject> ctorCaller)
  {
    _ctorCaller = ctorCaller;
  }

  public BusinessObject CreateBusinessObject(string myProperty)
  {
    if (...)
      return _ctorCaller (myProperty);
    else
      return null;
  }
}

:)

Solution 4

You could make the constructor on your MyBusinessObjectClass class internal, and move it and the factory into their own assembly. Now only the factory should be able to construct an instance of the class.

Solution 5

Apart from what Jon suggested, you could also either have the factory method (including the check) be a static method of BusinessObject in the first place. Then, have the constructor private, and everyone else will be forced to use the static method.

public class BusinessObject
{
  public static Create (string myProperty)
  {
    if (...)
      return new BusinessObject (myProperty);
    else
      return null;
  }
}

But the real question is - why do you have this requirement? Is it acceptable to move the factory or the factory method into the class?

Share:
53,122
User
Author by

User

Updated on October 24, 2020

Comments

  • User
    User over 3 years

    Recently I've been thinking about securing some of my code. I'm curious how one could make sure an object can never be created directly, but only via some method of a factory class. Let us say I have some "business object" class and I want to make sure any instance of this class will have a valid internal state. In order to achieve this I will need to perform some check before creating an object, probably in its constructor. This is all okay until I decide I want to make this check be a part of the business logic. So, how can I arrange for a business object to be creatable only through some method in my business logic class but never directly? The first natural desire to use a good old "friend" keyword of C++ will fall short with C#. So we need other options...

    Let's try some example:

    public MyBusinessObjectClass
    {
        public string MyProperty { get; private set; }
    
        public MyBusinessObjectClass (string myProperty)
        {
            MyProperty = myProperty;
        }
    }
    
    public MyBusinessLogicClass
    {
        public MyBusinessObjectClass CreateBusinessObject (string myProperty)
        {
            // Perform some check on myProperty
    
            if (true /* check is okay */)
                return new MyBusinessObjectClass (myProperty);
    
            return null;
        }
    }
    

    It's all okay until you remember you can still create MyBusinessObjectClass instance directly, without checking the input. I would like to exclude that technical possibility altogether.

    So, what does the community think about this?

  • User
    User over 15 years
    This is hardly a requirement. I just want to have a clean separation of business object and logic. Just as it is inappropriate to have these checks in pages' code-behind, I deem it inappropriate to have these checks in objects themselves. Well, maybe basic validation, but not really business rules.
  • User
    User over 15 years
    I thought about that but it effectively moves these checks into the business object itself, which I'm trying to avoid.
  • Jon Skeet
    Jon Skeet over 15 years
    @so-tester: You can still have the checks in the factory rather than the BusinessObject type.
  • pipTheGeek
    pipTheGeek over 15 years
    I don't understand this distinction either. Can someone explain why this is being done, and what code would be in the business object?
  • User
    User over 15 years
    It's just one approach that could be used. I want business object to be mainly data structures but not with all the field open for read/write. But the question really was about being able to instantiate an object only with the help of a factory method and not directly.
  • Ricardo Nolde
    Ricardo Nolde over 13 years
    Ah, you could also throw an exception instead of returning null.
  • Kiley Naro
    Kiley Naro over 12 years
    @JonSkeet I know this question is really old, but I'm curious as to what the advantage is to putting the CreateBusinessObject method inside of a nested Factory class instead of having that static method be a method directly of the BusinessObject class... can you recall your motivation for doing so?
  • Jon Skeet
    Jon Skeet over 12 years
    @KileyNaro: Well, that's what the question was asking for :) It doesn't necessarily confer many advantages, but it answers the question... there can be times when this is useful though - the builder pattern springs to mind. (In that case the builder would be the nested class, and it would have an instance method called Build.)
  • Grx70
    Grx70 about 11 years
    If you want to separate the logic and the structure of a class only for reviewing convenience, you could always use a partial class and have both in separate files...
  • Nikolai Samteladze
    Nikolai Samteladze over 10 years
    Very nice piece of code. Object creation logic is in a separate class and object can be created only using the factory.
  • Flater
    Flater over 10 years
    @Jim: I personally agree with your point, but professionally, this is done constantly. My current project is a webservice that takes a HTML string, cleans it up according to some preset rules, then returns the cleaned up string. I am required to go through 7 layers of my own code "because all our projects must be built from the same project template". It stands to reason that most people asking these questions on SO don't get the freedom to change the entire flow of their code.
  • Flater
    Flater over 10 years
    So you make sure the only working public constructor of the object requires a Factory, and that needed Factory parameter can only be instantiated by calling the Factory's static method? Seems like a working solution, but I get the feeling that snippets like public static IBusinessObject New(BusinessFactory factory) will raise many eyebrows if someone else maintains the code though.
  • Reuven Bass
    Reuven Bass over 10 years
    @Flater Agreed. I would change the parameter name factory into asFriend. In my code base it would show then as public static IBusinessObject New(BusinessFactory asFriend)
  • lapsus
    lapsus over 9 years
    I don't get it at all. How does it work? The factory cannot create new instances of IBusinessObject nor has it any intention (methods) to do so...?
  • lin
    lin about 9 years
    Please try my approach, The 'factory' is the container of the handler, and only it can create an instance for itself. with some modification, it may fit your needs.
  • Whyser
    Whyser over 8 years
    In your example, wouldn't the following be possible (which would not make sense)?: factory.DoWork();
  • Felix Keil
    Felix Keil over 8 years
    Cool. Is there some way that you can limit the creation of the BusinessObjectFactory to the static BusinessObject.GetFactory?
  • sara
    sara over 8 years
    there's no point in having a private default constructor if you have declared a custom one. also, in this case there is literally nothing to be gained from using a static "constructor" instead of just doing the validation in the real constructor (since it's part of the class anyway). it's even WORSE, since you can now get a null return value, opening up for NREs and "what the hell does this null mean?" questions.
  • Arash Motamedi
    Arash Motamedi over 8 years
    Any good way to require this architecture through an Interface/abstract base class? i.e. an interface/abstract base class that dictates that implementers should not expose a ctor.
  • Ricardo Nolde
    Ricardo Nolde about 8 years
    @Arash No. Interfaces can't define constructors, and an abstract class that defines a protected or internal constructor can't prevent inheriting classes from exposing it through a public constructor of its own.
  • yatskovsky
    yatskovsky over 7 years
    What is the advantage of this inversion?
  • Fabian Schmied
    Fabian Schmied over 7 years
    @yatskovsky It's just a way of ensuring that the object can only be instantiated in a controlled fashion while still being able to factor the creation logic into a dedicated class.