Reputation: 1893
I have classes that should have properties with private setters (or private fields and Readonly properties associated with it). It is all right if I have static factory methods in these classes to create instances. However lot of developers write that "Static factory methods is architectural black hole" as it is impossible to inherit static methods.
C# doesn't have friendly classes, hence I can't do it using Factories.
What do you think about using static factory methods?
Upvotes: 2
Views: 1866
Reputation: 2666
As a default i would create instances by passing the required arguments to the constructor. If the constructor has to many parameters you either need a parameter object or you are violating SRP. If you have multiple choices of creating the instances depending on arguments, AND the logic IS NOT complex than a static factory method is probably the best way to keep the creation logic inside the class.
If you have complex instance creating rules that depend on the parameters and maybe other factors you could use a factory, maybe a fluent factory, which gathers all the required parameters an performs the needed logic and then uses the class public constructor to create the object.
Upvotes: 2
Reputation: 13783
You have to make this "black hole" in one way or another. You could use constructors instead, which is easier. However, I find static methods nicer. They share almost all of the architectural properties of constructors except being a little bit better in that the constructor must always create a new instance, thus some implementation abstractions are not possible with constructors.
So, the answer is: use static methods please! :)
Upvotes: 1
Reputation: 15559
If the targets and the factory are not in the same assembly one way to get partial encapsulation of the write methods is to use a private interface implmentation that you keep out of client code.
internal interface IMyClassFactorable
{
string MyProperty{ set; }
}
public class MyClass : IMyClassFactorable
{
private string _myProperty;
public string MyPrperty { get { return _myProperty; } }
string IFactoryable.MyProperty { set { _myProperty = value; } }
}
or with internal setters if the factory and the targets are in the same assembly
public class MyClass
{
public string MyPrperty { get; internal set; }
}
Upvotes: 0
Reputation: 9085
I believe when people say static factory methods "... [are] an architectural black hole", they are referring to the problem that it's a mess to extend the factory methods. The judgement point is how complicated the created classes are. If they are heavyweight, then likely static factory methods are going to make a mess in the long run.
C# does have the "internal" modifier, which isn't a replacement for friend as far as others working on top of your classes, but when what matters is your ability to extend the factories in the future rather than others, you can package the factories and created classes as a a separate assembly and thus use "internal" like "friend".
And, yes, this is an issue in working with C#. Conflicting requirements that dropped support for the old friendly factory class, and it is painful. If you can't use "internal", and your factories are rendering heavyweight classes, there really isn't any alternative to adding an "InitInstance()" type method to the classes so the "manufacturing process" can be extended.
Upvotes: 1
Reputation: 14784
All readonly dependencies of a class should be injected by the constructor of this type. This makes the code easier to understand, debug and, most important, to test. So should really think about your class hierarchy if this is not possible. If you follow this principle carefully you can also use a dependency injection framework to resolve this dependencies at runtime.
Sample:
class Foo : IFoo
{
private readonly IBar bar;
private readonly IBaz baz;
public Foo(IBar bar, IBaz baz)
{
this.bar = bar;
this.baz = baz;
}
// Readonly properties for bar and baz, if needed.
}
Upvotes: 2
Reputation: 74530
I don't think the statement:
C# doesn't have friendly classes, hence I can't do it using Factories
Is really true.
The key is to not create the static factory method on the class that is performing the implementation. You don't escape strong coupling here.
You might want to look into dependency injection/inversion. Instead of having to worry about creating the factories, you set up how your objects are created through/code config; the DI framework provides the factories for you, as well as wiring up any dependencies that you indicate you need.
Upvotes: 1