Factory Template by selecting by property

I have a (growing) list of Data-Generators. The generator I need is created by the factory class. Generators implement a common interface, which includes, among other things, a static name string.

What I would like to do: Call the factory.Create method with a string parameter for the specified name. The create method finds a generator with this name and returns a new instance of the specified generator.

A bonus, in my opinion, is for this: I only need to add new generator classes without having to edit the factory.

Question:

  • Is this a good way to deal with this problem?
  • How can I find all the generators? Reflection on each implementation of the interface / each member of the namespace (unique to generators + their interface)?
  • Is this the right way to name the factory, or is it some other template?

In the end, I would call factory as follows (simplified):

 //Caller public DataModel GetData2() { var generator = new DataFactory().Create("Gen.2"); return generator.GetData(); } //Factory public class DataFactory { public AbstractDataGenerator Create(string type) { //Here the magic happens to find all implementations of IDataGenerator var allGenerators = GetImplementations(); var generator = allGenerators.FirstOrDefault(f => f.name == type); if (generator != null) return (AbstractDataGenerator)Activator.CreateInstance(generator); else return null; } } //Interface public abstract class AbstractDataGenerator { public static string name; public abstract DataModel GetData(); } //Data-Generators public class DataGen1 : AbstractDataGenerator { public static string name = "Gen.1"; public DataModel GetData() { return new DataModel("1"); } } public class DataGen2 : AbstractDataGenerator { public static string name = "Gen.2"; public DataModel GetData() { return new DataModel("2"); } } 

Should the magic of GetImplementations() in the factory be done through Reflection or something else? Should I use a completely different approach?

Since the answers relate to IoC and DI: this project already uses NInject, so it will be available. Switched from interface to abstract class.

+7
c # design-patterns factory
source share
2 answers

Is this a good way to deal with this problem?

Having a factory to get an instance of a boolean class that you need with some key, I believe this is a good way. This is a sample that I use myself. About how you have your key - I would prefer not to have it as a member of static (regardless of the fact that interfaces cannot contain static elements), but also as property and add a base class to IDataGenerator . This base class will have a constructor that gets name . That way, every new DataGenerator that you create will have to install it, and you won't forget.


The fact that name like string - I personally prefer to have it "strongly typed". I mean, if I pass Gen . 2 Gen . 2 instead of Gen.2 with strings, I will find this problem only at runtime. Other ways are possible (if you want, because a simple line is beautiful too - a matter of taste):

  • Replace strings with enum
  • Have a static class with static readonly strings for all your values ​​- then these values ​​are used in your code. You get the benefits of intellisense and you don’t get the string incorrectly, but better than an enumeration - you can simply pass strings that are not on the β€œlist”, so you can add new ones as add-ons.
  • Have a RequestGenerator object, each Generator will be an IDataGenerator<TGeneratorRequest> . This may be redundant, but if you have additional information needed to create a DataGenerator that is different from them, then consider it.

How can I find all the generators? Reflection on each implementation of the interface / each member of the namespace (unique to generators + their interface)?

Yes, reflection can be a good way to do this. However, I would suggest reading in Dependency Injection and IoC Containers , for example, Castle Windsor . There are things that already implement it for you, so why reinvent the wheel :)

DI is a concept of life change, in my opinion.

Is this the right way to name the factory, or is it some other template?

Yap. This is Factory

Should the magic GetImplementations () in the factory be executed via Reflection or something else?

See answer to question 2

+4
source share

Here the constructor's injector can REALLY shine. Learn dependency injection tools and use them! It also validates your Bonus request.

Here is what your factory might look like when entering a constructor:

 public class DataFactory { private Dictionary<string, IDataGenerator> generators; public DataFactory(IDataGenerator[] generatorReferences) { this.generators = generatorReferences .ToDictionary(k => k.name, v => v); } public IDataGenerator Create(string type) { IDataGenerator generator = null; this.generators.TryGetValue(type, out generator); return generator; } } 

Most DI software products have the ability to automatically scan assemblies for implementations of a certain type (for example, IDataGenerator) and register them with itself, when it creates an instance of your DataFactory, it will automatically include them.

+2
source share

All Articles