1

I am trying to make some generic factories for my service factories and dao factories and am running into some limitations.

Typically my service and dao factories look like this:

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;
    }
}

Then I tried doing a generic factories:

 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;
        }
    }

So they could used like this:

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

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

Here are the problems I am running into:

  1. Can't use static class as type constraint for generics, which I was trying to use for the EntityServiceFactory, because without it I don't know how to inject the appropriate dao.

  2. Can't have the factories derive from the Generic factories because I get an error like:

Static class 'Persons.PersonDaoFactory' cannot derive from type 'Entities.EntityDaoFactory'. Static classes must derive from object.

  1. Tried making them all non-static classes with private constructors to get around that but then I get:

'Persons.PersonService' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'serviceClass' in the generic type or method 'Entities.EntityServiceFactory

I was able to read why number 3 occurs on here, but that still doesn't solve my problems. I got the DaoFactory working, but it only works if the specific DaoClass doesn't need any dependency injection, otherwise error 3 pops up again.

Is there anyway to get these generic factories working using a different approach while still being able to use DI?

EDIT ----

I was able to get this sort of working, but it has some oddities. First I created a IEntityFactory interface:

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

Then changed the EntityDaoFactory to:

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;
        }
    }

So I could pass in the appropriate type parameters and change the EntityServiceFactory to:

 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;
        }
    }

So for a specific implementation such as with the Person object the calls look like:

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

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

So it's working now, but the oddities are:

  1. You can instantiate a factory, which was required (as far as I know the only way to do it?) for the EntityServiceFactory, but for someone using my API there would be no reason for them to do it but they still could.

  2. Services and DAOs which have dependency requirements can now be instantiated with no parameters, which would break the instantiated class methods (but I had to do it to be able to use it as a type parameter). They shouldn't even ever by instantiating these objects anyway but they can now and do so incorrectly.

Also a final problem I just thought of is this solution doesn't really handle a variable amount of dependencies well. Still wonder if there is a better approach for this?

Conclusion: I think in the end even though it works, I gave up a lot of order to have that generic factory, which isn't that flexible and not giving me much, so I probably wouldn't use it in this case due to the limitations.

SventoryMang
  • 10,275
  • 15
  • 70
  • 113
  • 1
    Looks like all your problems is because you've marked factories as static which does not make sense moreover considering you are going to use DI which becomes to reduce such static dependencies – sll Dec 02 '11 at 19:14
  • 2
    Those bear a striking resemblance to Singletons. – Austin Salonen Dec 02 '11 at 19:15
  • 1
    You don't need to build a factory if you only ever need to build one of something. – Dan Bryant Dec 02 '11 at 19:18
  • http://en.wikipedia.org/wiki/Factory_pattern "For example, using this definition, singletons implemented by the singleton pattern are formal factories." – SventoryMang Dec 02 '11 at 19:43
  • @DOTang: Indeed. But you wouldn't use Singletons in a place where you need to be able to instantiate something (`new()` requirement). – Austin Salonen Dec 02 '11 at 19:57
  • Why not? In a Singleton you instantiate a class just one time and that is what I am doing. And if not, what do you use? – SventoryMang Dec 02 '11 at 20:17

2 Answers2

2

First of all, you are NOT using dependency injection. Depencency injection has nothing to do with providing type parameters to a generic class / method.

The errors occur because you are violating C#'s rules. You have to change your code to conform with them. So, make your classes non-static and do not use private constructors. You can replace a static class with a singleton instance and use protected constructors to avoid uncontroller instantiation.

Ondrej Tucny
  • 27,626
  • 6
  • 70
  • 90
  • Yes I am using dependency injection, the ServiceFactory injects the appropriate Dao class in a new instance of the Service class and it does matter because I can't use the Service class as a generic type parameter unless it has a public empty contstructor, which I have now tried and that was able to fix some of my problems, but now a person using my API can instantiate a service directly (which they shouldn't even be doing) without the dao constructor, which would breakstuff. Which you may have touched upon that in your last sentence but I am not sure what you mean, can you provide an example? – SventoryMang Dec 02 '11 at 20:28
  • I edited my post, I was able to get it sort of working by removing all statics and private constructors, but there are some oddities which I noted in my edit. – SventoryMang Dec 02 '11 at 20:41
  • Marking this as an answer because it fixed my specific problems in my first go at it, but it gave up too much imo to be worthwhile of using it. – SventoryMang Dec 02 '11 at 20:55
0

I know that this question is really old, but I stumbled across it, so I figure I would give an answer.

The following compiles and does what you are looking to do:

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);
    }
}

Now unless you are planning on using these types from within a composition root, I strongly recommend against doing the above solution since some of your dependencies are hidden and worse, are fixed to a limited set of parameters. Instead try something like this for a more DI/composition root friendly solution.

Community
  • 1
  • 1
Tyree Jackson
  • 2,588
  • 16
  • 22