Factory pattern in C#: How to ensure an object instance can only be created by a factory class?
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?
User
Updated on October 24, 2020Comments
-
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 over 15 yearsThis 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 over 15 yearsI thought about that but it effectively moves these checks into the business object itself, which I'm trying to avoid.
-
Jon Skeet over 15 years@so-tester: You can still have the checks in the factory rather than the BusinessObject type.
-
pipTheGeek over 15 yearsI don't understand this distinction either. Can someone explain why this is being done, and what code would be in the business object?
-
User over 15 yearsIt'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 over 13 yearsAh, you could also throw an exception instead of returning null.
-
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 nestedFactory
class instead of having that static method be a method directly of theBusinessObject
class... can you recall your motivation for doing so? -
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 about 11 yearsIf 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 over 10 yearsVery nice piece of code. Object creation logic is in a separate class and object can be created only using the factory.
-
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 over 10 yearsSo 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 over 10 years@Flater Agreed. I would change the parameter name
factory
intoasFriend
. In my code base it would show then aspublic static IBusinessObject New(BusinessFactory asFriend)
-
lapsus over 9 yearsI 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 about 9 yearsPlease 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 over 8 yearsIn your example, wouldn't the following be possible (which would not make sense)?: factory.DoWork();
-
Felix Keil over 8 yearsCool. Is there some way that you can limit the creation of the BusinessObjectFactory to the static BusinessObject.GetFactory?
-
sara over 8 yearsthere'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 over 8 yearsAny 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 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 over 7 yearsWhat is the advantage of this inversion?
-
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.