Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)

like image 782
Heinz Kessler Avatar asked Mar 03 '23 19:03

Heinz Kessler


2 Answers

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...
    }   
}
like image 159
Sweeper Avatar answered Mar 15 '23 23:03

Sweeper


public abstract class T { }

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

    private class TImpl : T { }
}
like image 27
Alex Avatar answered Mar 15 '23 23:03

Alex