【问题标题】:Generic factories impossible when requiring dependency injection?需要依赖注入时不可能实现通用工厂?
【发布时间】:2011-12-02 19:11:17
【问题描述】:

我正在尝试为我的服务工厂和 dao 工厂创建一些通用工厂,但遇到了一些限制。

我的服务和 dao 工厂通常如下所示:

public static class PersonServiceFactory
{
    private static PersonService personService;

    public static PersonService GetInstance()
    {
        if (personService == null)
        {
            PersonDao personDao = PersonDaoFactory.GetInstance();
            personService = new PersonService(personDao);

        }

        return personService;
    }
}

public static class PersonDaoFactory
{
    private static PersonDao personDao;

    internal static PersonDao GetInstance()
    {
        if (personDao == null)
        {
            personDao = new PersonDao();

        }

        return personDao;
    }
}

然后我尝试做一个通用工厂:

 public abstract class EntityDaoFactory<daoClass>
        where daoClass : class, new()
    {
        private static daoClass factorySupportClass;

        internal static daoClass GetInstance()
        {
            if (factorySupportClass == null)
            {
                factorySupportClass = new daoClass();

            }

            return factorySupportClass;
        }
    }

  public abstract class EntityServiceFactory<serviceClass, daoClass>
        where serviceClass : class, new()
        where daoClass : class
    {
        private static serviceClass factorySupportClass;

        internal static serviceClass GetInstance()
        {
            if (factorySupportClass == null)
            {
                //daoClass daoSupportClass = *how to get daoSupportClassfactory.GetInstance(); here?*
                factorySupportClass = new serviceClass(daoSupportClass);

            }

            return factorySupportClass;
        }
    }

所以他们可以这样使用:

public static class PersonDaoFactory : Entities.EntityDaoFactory<PersonDao>
{
}

public static class PersonServiceFactory : Entities.EntityServiceFactory<PersonService, PersonDaoFactory>
{
}

以下是我遇到的问题:

  1. 不能使用静态类作为泛型的类型约束,我试图将其用于 EntityServiceFactory,因为没有它我不知道如何注入适当的 dao。

  2. 不能让工厂派生自通用工厂,因为我收到如下错误:

静态类“Persons.PersonDaoFactory”不能 从类型派生 '实体.EntityDaoFactory'。 静态类必须派生自对象。

  1. 尝试使用私有构造函数将它们全部设为非静态类以解决该问题,但后来我得到:

'Persons.PersonService' 必须是具有公共的非抽象类型 无参数构造函数,以便将其用作参数 泛型类型或方法中的“serviceClass” 'Entity.EntityServiceFactory

我能够读懂为什么会出现第 3 个数字,但这仍然不能解决我的问题。我让 DaoFactory 工作了,但它只有在特定的 DaoClass 不需要任何依赖注入时才有效,否则会再次弹出错误 3。

有没有办法让这些通用工厂使用不同的方法工作,同时仍然能够使用 DI?

编辑----

我能够进行这种工作,但它有一些奇怪之处。首先我创建了一个 IEntityFactory 接口:

 public interface IEntityFactory<T>
    where T : class
{
    T GetInstance();
}

然后将EntityDaoFactory改为:

public abstract class EntityDaoFactory<daoClass> : IEntityFactory<daoClass>
        where daoClass : class, new()
    {
        private static daoClass factorySupportClass;

        public daoClass GetInstance()
        {
            if (factorySupportClass == null)
            {
                factorySupportClass = new daoClass();

            }

            return factorySupportClass;
        }
    }

所以我可以传入适当的类型参数并将 EntityServiceFactory 更改为:

 public abstract class EntityServiceFactory<serviceClass, daoClass, daoFactoryClass>
        where serviceClass : class, new()
        where daoClass : class, new()
        where daoFactoryClass : IEntityFactory<daoClass>, new()
    {
        private static serviceClass factorySupportClass;

        public static serviceClass GetInstance()
        {
            if (factorySupportClass == null)
            {
                daoFactoryClass daoSupportFactory = new daoFactoryClass();
                daoClass daoSupportClass = daoSupportFactory.GetInstance();
                factorySupportClass = new serviceClass();

            }

            return factorySupportClass;
        }
    }

因此,对于特定的实现,例如 Person 对象,调用如下所示:

public class PersonDaoFactory : Entities.EntityDaoFactory<PersonDao>
{
}

 public class PersonServiceFactory : Entities.EntityServiceFactory<PersonService, PersonDao, PersonDaoFactory>
{
}

所以它现在可以工作了,但奇怪的是:

  1. 您可以实例化一个工厂,这是 EntityServiceFactory 所必需的(据我所知,这是唯一的方法吗?),但对于使用我的 API 的人来说,他们没有理由这样做,但是他们仍然可以。

  2. 现在可以在没有参数的情况下实例化具有依赖性要求的服务和 DAO,这会破坏实例化的类方法(但我必须这样做才能将其用作类型参数)。他们甚至不应该通过实例化这些对象,但他们现在可以并且错误地这样做。

我刚刚想到的最后一个问题是这个解决方案并不能很好地处理可变数量的依赖关系。仍然想知道是否有更好的方法来解决这个问题?

结论:我认为最终即使它有效,我还是放弃了很多订单来拥有那个通用工厂,它不是那么灵活并且没有给我太多,所以我可能由于限制,在这种情况下不会使用它。

【问题讨论】:

  • 看起来你所有的问题都是因为你已经将工厂标记为静态这没有意义此外考虑到你将使用 DI 来减少这种静态依赖
  • 这些与单身人士有着惊人的相似之处。
  • 如果你只需要建造一个东西,你就不需要建造工厂。
  • en.wikipedia.org/wiki/Factory_pattern "例如,使用这个定义,单例模式实现的单例就是正式工厂。"
  • @DOTang:确实。但是你不会在需要实例化某些东西的地方使用单例(new() 要求)。

标签: c# .net generics factory


【解决方案1】:

首先,您使用依赖注入。 Depencency injection 与向泛型类/方法提供类型参数无关。

出现错误是因为您违反了 C# 规则。您必须更改代码以符合它们。所以,让你的类是非静态的,不要使用私有构造函数。您可以将静态类替换为单例实例,并使用受保护的构造函数来避免非控制器实例化。

【讨论】:

  • 是的,我正在使用依赖注入,ServiceFactory 会在 Service 类的新实例中注入适当的 Dao 类,这很重要,因为我不能将 Service 类用作泛型类型参数,除非它有一个公共的空构造函数,我现在已经尝试过了,它能够解决我的一些问题,但是现在使用我的 API 的人可以在没有 dao 构造函数的情况下直接实例化服务(他们甚至不应该这样做),它会吃不饱。您可能在最后一句话中提到了这一点,但我不确定您的意思,您能举个例子吗?
  • 我编辑了我的帖子,我能够通过删除所有静态和私有构造函数来使其正常工作,但我在编辑中注意到了一些奇怪的地方。
  • 将此标记为答案,因为它在我第一次尝试时解决了我的具体问题,但它放弃了太多 imo 不值得使用它。
【解决方案2】:

我知道这个问题很老了,但我偶然发现了它,所以我想我会给出答案。

以下编译并执行您要执行的操作:

public abstract class Entity<serviceFactory, serviceClass, daoFactory, daoClass>
    where daoFactory : Entity<serviceFactory, serviceClass, daoFactory, daoClass>.DaoFactory, new()
    where daoClass : class, new()
    where serviceFactory : Entity<serviceFactory, serviceClass, daoFactory, daoClass>.ServiceFactory, new()
    where serviceClass : class, new()
{
    public abstract class DaoFactory
    {
        private static daoClass factorySupportClass;

        internal static daoClass GetInstance()
        {
            if (factorySupportClass == null)
            {
                factorySupportClass = new daoFactory().createDao();

            }

            return factorySupportClass;
        }

        protected abstract daoClass createDao();
    }

    public abstract class ServiceFactory
    {
        private static serviceClass factorySupportClass;

        internal static serviceClass GetInstance()
        {
            if (factorySupportClass == null)
            {
                daoClass daoSupportClass = DaoFactory.GetInstance();
                factorySupportClass = new serviceFactory().createService(daoSupportClass);

            }

            return factorySupportClass;
        }
        protected abstract serviceClass createService(daoClass dao);
    }
}

现在,除非您打算在组合根中使用这些类型,否则我强烈建议您不要执行上述解决方案,因为您的一些依赖项是隐藏的,更糟糕​​的是,它们被固定为一组有限的参数。相反,请尝试使用 this 之类的方法来获得更适合 DI/composition 根的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2012-08-09
    • 2011-09-01
    • 2015-08-25
    • 1970-01-01
    相关资源
    最近更新 更多