Heinz Kessler
Heinz Kessler

Reputation: 1670

Factory pattern: Restrict object construction to factory

I have a class T and a factory TFactory that creates objects of type T. I want to make sure that only the factory is allowed to create new T objects.

A halfhearted solution would be to require the factory as a parameter in T's constructor, for the only purpose that only somebody who at least brings a factory object can create T's:

class T
{
    public T(TFactory Tf)
    {
        if (!(Tf is TFactory))
            throw new InvalidOperationException("No factory provided");
    }
}

But wherever a TFactory is at hand, one could construct T's. Another approach would be to check via stack tracing, if the constructor call really came from within a TFactory, but this seems overkill to me.

A third apporach would be to put both T and TFactory in an assembly of their own, ad make T's constructor internal. But a new project and assembly just for this purpose?

Any better idea anybody? (Although my code is C#, this is probably a more general question)

Upvotes: 4

Views: 1835

Answers (3)

Guy Caeser
Guy Caeser

Reputation: 21

The second approach is the worst one. That behavior is absolutely unobvious and unclear to a client. Stack tracing also slows down execution. The 1st and the 2nd make sense.

If you want to have total control of instance creation put it into the type. Use a factory method. Remember, one should be reasonable when putting constraint on instance creation. E.g. the instance should be initiated with a polymorphal (virtual) method. One can't call such a method from a constructor (a very bad practice), so the method should be called after construction. For not to put that responsibility on the client, hide the constructor from one and provide a factory method.

abstract class Base
{
    protected abstract void Initialize();
}

class Derived : Base
{
    protected Derived() { /* ... */}

    protected override void Initialize() { /* ... */}

    public Derived CreateDerived()
    {
        var derived = new Derived();
        derived.Initialize();
        return derived;
    }
}

Upvotes: 2

CSDev
CSDev

Reputation: 3235

public abstract class T { }

public class TFactory
{
    public T CreateT() => new TImpl();

    private class TImpl : T { }
}

Upvotes: 2

Sweeper
Sweeper

Reputation: 270790

Here's something very similar to your third approach: declare the factory as a inner class of T, and make T's constructor private:

public class T {
    public class Factory {
        public T GetT() {
            return new T(); // simple implementation just for an example here
        }
    }

    private T() {}
}

Since Factory is inside T, it can access the private constructor, but outside code cannot. If you don't want to create a separate assembly, you could consider this approach.

Note that you could still put the factory class and T in two different files, with partial classes:

public partial class T {
    private T() {}
    // other stuff about T here...
}

// in another file

public partial class T {
    public class Factory {
        public T GetT() {
            return new T();
        }
        // other stuff about Factory here...
    }   
}

Upvotes: 4

Related Questions