Factory pattern with static registration

2019-08-09 18:10发布

问题:

I'm having a problem when trying to register my types using their static constructors, with the following factory:

 public class Factory<T>
{
    public static Factory<T> Instance { get { return _instance; } }

    private static Factory<T> _instance = new Factory<T>();
    private Factory() { }
    static Factory() { }

    static Dictionary<string, Type> _registeredType = new Dictionary<string, Type>();

    public void Register(string id, T obj)
    {
        if (obj.GetType().IsAbstract || obj.GetType().IsInterface)
            throw new ArgumentException("Cannot create instance of interface or abstract class");

        _registeredType.Add(id, obj.GetType());
    }

    public T Create(string id, params object[] parameters)
    {
        Type type;

        if(!_registeredType.TryGetValue(id, out type))
            throw new UnsupportedShapeException(id);

        return (T)Activator.CreateInstance(type, parameters);
    }
} 

Then if I use a static constructor for registration it doesn't work:

    public interface IShape
{
    string print { get; }
}

public class Circle : IShape
{
    static Circle()
    {
        Factory<IShape>.Instance.Register("Circle", new Circle());
    }

    public string print
    {
        get
        {
            return "Circle";
        }
    }
}

Where am I going wrong? The factory appears to set up fine but I just can't get the ctor to work. Cheers.

回答1:

It's not an answer but an advice. First, when you use generic class actually CLR creates class for every implementation. This classes will have different static variables and you can not use one factory for all classes. The good news is that you can use generic methods instead of generic class. And you even do not need to create an instance of T object:

public class Factory
{
    public static Factory Instance { get { return _instance; } }

    private static Factory _instance = new Factory();
    private Factory() { }

    static Dictionary<string, Type> _registeredType = new Dictionary<string, Type>();

    public void Register<T>(string id)
    {
        var type = typeof(T);
        if (type.IsAbstract || type.IsInterface)
            throw new ArgumentException("Cannot create instance of interface or abstract class");

        _registeredType.Add(id, type);
    }

    public T Create<T>(string id, params object[] parameters)
    {
        Type type;

        if(!_registeredType.TryGetValue(id, out type))
            throw new UnsupportedShapeException(id);

        return (T) Activator.CreateInstance(type, parameters);
    }
} 

Now you can use Factory to register and resolve objects:

Factory.Instance.Register<Circle>("Circle");
var firstCircle = Factory.Instance.Create<Circle>("Circle");
var secondCircle = Factory.Instance.Create<IShape>("Circle");


回答2:

I am not 100% sure I know what you are going after, however, it would probably be best to make controller'esqe classes that contain your factory instantiation. However, constructor injection will not work on static classes or descendants.

public static class StaticFactoryClassController
{
    private static readonly IStaticFactoryService service=AppServiceFactory.Instance.Create<IStaticFactoryService>();

    public static void DoSomething() 
    {
        Service srv = new StaticFactoryClassService(service);
        srv.DoSomething(); 
    }
}

And with that you could create a service class--

public class StaticFactoryClassService
{
    private readonly IStaticFactoryService service;

    public StaticFactoryClassService(IStaticFactoryService service)
    {
        this.service = service;
    }

    public void DoSomething()
    {
       this.service.DoSomething();
    }
}

And finally your binding interface--

public interface IStaticFactoryService
{
    DoSomething();
}