tags:

views:

557

answers:

17

What are the advantages and when is it appropriate to use a static constructor?

public class MyClass
{
    protected MyClass()
    {
    }

    public static MyClass Create()
    {
        return new MyClass();
    }
}

and then creating an instance of the class via

MyClass myClass = MyClass.Create();

as opposed to just having a public constructor and creating objects using

MyClass myClass = new MyClass();

I can see the first approach is useful if the Create method returns an instance of an interface that the class implements...it would force callers create instances of the interface rather than the specific type.

+1  A: 

This pattern is typically used in the Singleton pattern. It is useful for when you have a class or facade for a class that should only be instantiated once during a program's life, typically because of the resources that the object will use.

How to in C#

Wayne Hartman
Singleton pattern would return a reference to the same object, whereas factory pattern creates multiple instances which may share data.
Billy ONeal
As BillyONeal mentioned, this is -not- the Singleton pattern; Singleton forces only one instance of a class to ever be created. A great example of when you might want to use the Singleton pattern is for settings classes where only one should ever exist.
Ed Altorfer
While both of you are correct and his code does not necessarily convey a singletone, please remember that his original question revolves around the use of *static construction* which both the factory and singleton use.
Wayne Hartman
+1  A: 

There are various reasons you might do this, for instance to always return an instance from a fixed object pool (including a Singleton object), or as you say, to return instances of an interface.

But if you don't have a clear reason to do it, don't.

Matthew Flaschen
+2  A: 

Might be useful in cases where multiple class instances share the same block of initialized data -- this is the OOP factory pattern.

An example would be a class which connects to a database -- only one connection is required, and can be shared by all instances of the class.

http://en.wikipedia.org/wiki/Factory_pattern

Billy3

Billy ONeal
This doesn't require a factory method. It can be accomplished with just a static connection variable.
Matthew Flaschen
True. But that is not how the OP's code is written.
Billy ONeal
+1  A: 

This approach is only commonly used for Singletons, otherwise this approach is unorthodox. Don't use until you understand what it's trying to do.

Jon Limjap
Thanks Jon, I do know how, when and why to use Singletons but I'm pretty sure i've seen code samples that use this that are not Singletons...They could of course be wrong which is why I asked the question :-)
Michael Prewecki
Don't use what? Singletons or the static constructor creational pattern. I'd agree with the former (avoid singletons) but would otherwise disagree. The builder / factory pattern is quite standard, and the OP is asking why in order to understand the use of the pattern.
Robert Paulson
+13  A: 

This is the factory pattern, and it could often be used to produce a subclass, but allow the parameters to the static method determine which one.

It could also be used if a new object isn't always required, for example in a pooling implementation.

It can also be used if all instances of the object needs to be cached or otherwise registered upon creation. This ensures that the client doesn't forget to do that.

And of course, it is part and parcel of the Singleton pattern.

Yishai
I would add to this answer Robert Paulson's answer regarding "doing more than simple creation" as that would seem to complete this answer or at least extend upon the "cached or otherwise registered portion of the answer".
Michael Prewecki
+1  A: 

This is nice way of forcing MyClass to be final, if you use private constructor. That way subclasses cannot be created, because their constructor cannot access super's constructor.

Another advantage is when you have one parameter for the constructor. Then you can name the creation with emulating named arguments:

public static MyClass createWithDays(int days) {
...
}

Now compare new MyClass(5) to MyClass.createWithDays(5)

egaga
+6  A: 

This is not a singleton...Create would return the same instance every time if it was.

This is a factory pattern. I would normally do this with interfaces not classes, so I have to stretch here, but a contrived example would be:

public static MyClass Create()
{
    if(OS == Windows)
        return new MyDerivedClassForWindows();
    else if(OS == Linux)
        return new MyDerivedClassForLinux();
    etc....
}
ratchetr
Would you return MyClass or IMyClass...assuming of MyClass isn't an interface but IMyClass is (I mean that's just convention but you see my point).
Michael Prewecki
I would return IMyClass. The Mac folks probably won't want to derive from MyClass (just for the sake of being different), but they'll have to at least implement IMyClass if they want to play in my sandbox.
ratchetr
A: 

Apart from when it's a singleton, having a "static factory method" such as MyClass.Create can be useful if the person who implements MyClass.Create might want to return a subclass of MyClass ... for example during testing it could return an instance of the MyClassWithExtraTestingFunctionality subclass ... or, depending on a configuration option, an instance of the MyClassBeingRemotedOverTheNetwork subclass ...

ChrisW
A: 

This is also commonly used when you want the framework, class or some other configuration to determine WHERE the object will actually be created. When you use the new constructor approach, it is created locally. If you use this approach, it can potentially be created in remotely via a service call and returned, etc. This is the approach taken by Rocky Lhotka in the CSLA framework.

Adam Carr
+1  A: 

Many of the other answers have covered specific occasions where this idea may be useful. The idea of encapsulating instance creation is used in many IoC frameworks such as Spring, Castle and so on. The idea is that by centralizing instance creation, you can customize the configuration of your application to use different set of objects. A common example is logging. By changing the configuration, you can tell your logger factory to produce different instances of your logging classes according to the situation.

If applied this idea can lead to very loosely coupled systems, that may easily be changed after deployment or even at runtime. However, the complexity increases as you have another level of indirection.

Brian Rasmussen
+3  A: 

Another reason, demonstrated by Guid.NewGuid() static method, is if the type is a struct. In this case, the CLR requires that the default parameterless constructor creates a new instance with all the fields initialized to default values. In the case of Guid, this means:

Guid g = new Guid();

would be Guid.Empty. Obviously you want the ability to create a new Guid that is randomized, so the Guid.NewGuid() method is a way of doing that.

Josh Einstein
The Guid class is pretty poor naming-wise - the not-obviously-named NewGuid() is the only way to create a new (random) Guid as opposed to the constructors which just create Guids from existing data. Your answer observes reality, but doesn't answer the question why. Despite poor naming in the Guid class, you need to think about why Guid.NewGuid() is any different than new Guid().
Robert Paulson
+1  A: 

A static Constructor is also a good way to give more explicit names to your constructor. It can also be usefull to for default parameter

ex: Myclass.create(); intead of new Myclass(defaultParam1,defaultParam2 ... )

Joshua Bloch talks about it in effective Java (item 1)

Johnny Blaze
+4  A: 

The particular example you've posted wouldn't really have any advantage over using a normal constructor. There are two common patterns, however, which use a method like this to yield an object:

Singleton Pattern

The singleton pattern can be used when you want to prevent multiple instances of an object from being created but still want to leverage the object-oriented aspects of a class (e.g., fields, properties, parameterless methods). Example:

public class MySingletonClass
{
    private MySingletonClass currentInstance = null;

    public MySingletonClass CreateInstance()
    {
         if (currentInstance == null)
         {
              currentInstance = new MySingletonClass();
         }
         else
         {
              return currentInstance;
         }
    }
}

Factory Pattern

The factory pattern is a great opportunity to abstract the creation of concrete classes; for example, let's assume for a moment that you have some XML, and depending on which node (NodeA, NodeB, or NodeC) you see in the XML, you have a different class that will process it. Example:

public class MyXmlProcessorFactory
{
    public static IMyXmlProcessor GetMyXmlProcessor(XmlDocument document)
    {
         XmlNode rootNode = document.DocumentElement;

         if (rootNode.SelectSingleNode("NodeA") != null)
         {
              return new NodeAMyXmlProcessor();
         }
         else if (rootNode.SelectSingleNode("NodeB") != null)
         {
              return new NodeBMyXmlProcessor();
         }
         else if (rootNode.SelectSingleNode("NodeC") != null)
         {
              return new NodeCMyXmlProcessor();
         }
         else
         {
              return new DefaultMyXmlProcessor();
         }
    }
}
Ed Altorfer
+3  A: 

You are correct. This is not a Singleton pattern. It is a Factory pattern.

Use of Create() instead of new gives allows you to give meaningful names to the methods thus giving the user more clarity

Take this eg:

public class User
{
    public int id;
    public string userName;
    public string password;
    public string role;

    private User() { }

    public static User CreateByCredentials(string uid, string pwd)
    {
        User user = new User();
        user.userName = uid;
        user.password = pwd;
        return user;
    }

    public static User CreateById(int id)
    {
        User user = new User();
        user.id = id;
        return user;
    }

}

There are two advantages to this approach:

  1. We can return a null object, which is impossible to do with a constructor (This may or may not be useful in all cases.)
  2. If there are a lot of different ways to create an object, it gives you the chance to provide more meaningful function names. In the example you have User.CreateByCredentials (string username, string password) & User.CreateById(int id). You can accomplish the same functionality with constructor overloading, but rarely with the same clarity.
Rashmi Pandit
+1  A: 

More formally, it's usually referred to as Replace Constructor with Factory Method

You want to do more than simple construction when you create an object.

i.e. by using a factory method, you can be more explicit, and have more creation options available to the code over a simple constructor.

I'd recommend the book Refactoring: Improving the Design of Existing Code (Fowler)

Robert Paulson
A: 

Also this could be used in the case of lazy loading. Where you want the object to be around for some reason, but don't want to do all the heavy lifting involved in the real constructor unless needed. So you create a separate method Create and call it when you're ready for the heavy lifting.

Also @Rashmi Pandit wrote:

   public static User CreateByCredentials(string uid, string pwd)
    {
       ....
    }

    public static User CreateById(int id)
    {
    ...
    }

To your response, can't you just use overloaded constructors with different method signatures instead of creating two different create methods?

Lazy-loading isn't affected by the creational pattern. From a code readability view, @Rashmi's code is self documenting, where the constructors new User(string, string) or new User(int) are not quite so intuitive.
Robert Paulson
A: 

Note that you can only use constructor initializes when using the constructor approach.

    public void Example()
    {
        var person = new Person
                         {
                             GivenName = "John",
                             FamilyName = "Smith",
                             Address = new Address
                                           {
                                               Street = "Wallace",
                                               Number = 12
                                           },
                             PhoneNumbers = new List<PhoneNumber>
                                                {
                                                    new PhoneNumber
                                                        {
                                                            Number = 1234234,
                                                            AreaCode = 02
                                                        },
                                                    new PhoneNumber
                                                        {
                                                            Number = 1234234, AreaCode = 02
                                                        }
                                                }
                         };
    }

    internal class PhoneNumber
    {
        public int AreaCode { get; set; }

        public int Number { get; set; }
    }

    internal class Address
    {
        public int Number { get; set; }

        public string Street { get; set; }
    }

    internal class Person
    {
        public Address Address { get; set; }

        public string GivenName { get; set; }

        public string FamilyName { get; set; }

        public List<PhoneNumber> PhoneNumbers { get; set; }
    }
}
Simon