tags:

views:

234

answers:

8

How do I make sure that a certain class is only instantiated by a factory and not by calling new directly?

EDIT: I need the factory to be a separate class (for dependency injection purposes) so I can't make it a static method of the class to be instantiated, and so I can't make new private.

+9  A: 

Make its constructors private and supply the factory method as a static method on the class itself.

In most cases you can just make the constructors internal, allowing you to break the factory out into its own class - I've found it's often not worth trying to prevent my own team from using new to create instances within the class' assembly.

Jeff Sternal
+3  A: 

Make the constructor internal and house the factory in the same assembly.

public MyClass
{
    internal MyClass()
    {
    }
}

in same assembly

public MyClassGenerator
{
    public static CreateMyClass()
    {
        return new MyClass();
    }
}

If the factory can't be in the same assembly or this method doesn't work for you, look to Dan's answer

s_hewitt
A: 

Ctrl+Shift+F

Entire Solution

"new MyClassName"

On a serious note: private constructor.

Andy_Vulhop
+13  A: 

If the factory is in the same assembly and you only need protection against external assemblies instantiating the class, you can make the constructor internal. The only way I know to prevent this for all other classes (including those in the same assembly) is to make the instantiated class a nested private class of the factory and only expose it as an interface. If the class is its own factory (a static factory method), then you can make the constructor private, as others have mentioned.

Dan Bryant
+1 - if you really need this, that's how to get it done.
Jeff Sternal
+1  A: 

It will always be created by calling new somewhere, but if you only want that to happen in your factory class, you can set all the constructors to Internal (or Private, and use a Public Static factory method on the same class).

FacticiusVir
A: 

I do not like to have the factory on the type itself especially if it is a domain object. Have it internal if you are having a separate class as factory (which I think you should). Use InternalVisible attribute if the factory is on the different assembly.

Aliostad
+1  A: 

Many people have mentioned using internal, but you can also make your constructors protected and derive a class that just has the static factory method in it. This doesn't prevent others from doing the same thing, but does a pretty good job at restricting direct access to your constructors.

Mike
+2  A: 

If, for some reason, you need the factory and the constructed class to be in separate assemblies (which means simply using internal won't work), and you can ensure that your factory gets a chance to run first, you can do this:

// In factory assembly:

public class Factory
{
    public Factory()
    {
        token = new object();
        MyClass.StoreCreateToken(token);
    }

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

    private object token;
}

// In other assembly:

public class MyClass
{
    public static void StoreCreateToken(object token)
    {
        if (token != null) throw new InvalidOperationException(
            "Only one factory can create MyClass.");

        this.token = token;
    }

    public MyClass(object token)
    {
        if (this.token != token) throw new InvalidOperationException(
            "Need an appropriate token to create MyClass.");
    }

    private static object token;
}

Yes, it's cumbersome and awkward. But there may be weird situations where this is actually a good solution.

munificent
I like this, except there are 2 problems... (1) Your example seems to allow me to use only 1 factory. I would like to allow many factories to be created (perhaps there are different flavors of factory) the only requirement is that an object of MyClass must be created using an object of Factory. (2) What if I am using generics with a new() constraint and thus MyClass needs to have a parameterless constructor? Your example wouldn't work in that scenario.
JoelFan
"Your example seems to allow me to use only 1 factory." Make `token` static or share it among the different factory instances some other way. Anything that has access to the token can create instances of `MyClass` "What if I am using generics with a new() constraint and thus MyClass needs to have a parameterless constructor?" Then you don't need a factory either.
munificent