I would like some feedback on the implementation of the following factory:
public enum DietType {Carnivore, Herbivore, Omnivore};
[AttributeUsage(System.AttributeTargets.Class)]
public class DietTypeAttribute : Attribute
{
public DietType dietType { get; private set; }
public DietTypeAttribute(DietType dietType)
{
this.dietType = dietType;
}
}
public abstract class Diet { }
[DietTypeAttribute(DietType.Carnivore)]
public class Carnivore : Diet
{
}
[DietTypeAttribute(DietType.Herbivore)]
public class Herbivore : Diet
{
}
abstract class AbstractFactory<T> where T : class
{
protected Dictionary<Enum, Type> types;
protected AbstractFactory()
{
}
public T CreateInstance(Enum id, params object[] param)
{
return (T)Activator.CreateInstance(types[id], param);
}
}
class DietFactory : AbstractFactory<Diet>
{
public DietFactory()
{
types = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
let attributes = type.GetCustomAttributes(typeof(DietTypeAttribute), true)
where (attributes.Any()) && (typeof(Diet).IsAssignableFrom(type)) && (type.IsClass)
select
new
{
dietEnum = (Enum)((DietTypeAttribute)attributes.First()).dietType,
dietType = type
}).ToDictionary(x => x.dietEnum, x => x.dietType);
}
}
Usage:
static void Main(string[] args)
{
AbstractFactory<Diet> factory = new DietFactory();
Diet diet = factory.CreateInstance(DietType.Carnivore);
}
The main idea is to self register the classes with the use of enums instead of strings. I'm struggling to find a way to make the registration "generic", so i can avoid to specifying the attribute class on the LINQ query.
Any help is welcomed!
Try something like this..
public enum DietType {Carnivore, Herbivore, Omnivore};
public class FactoryAttribute : Attribute
{
public Object Something { get; protected set; }
}
[AttributeUsage(System.AttributeTargets.Class)]
public class DietTypeAttribute : FactoryAttribute
{
public DietTypeAttribute(DietType dietType)
{
this.Something = dietType;
}
}
public abstract class Diet { }
[DietTypeAttribute(DietType.Carnivore)]
public class Carnivore : Diet
{
}
[DietTypeAttribute(DietType.Herbivore)]
public class Herbivore : Diet
{
}
abstract class AbstractFactory<T> where T : class
{
protected Dictionary<Enum, Type> types;
protected AbstractFactory()
{
}
protected void Register<TEnumType, TSubType>()
where TEnumType: FactoryAttribute
{
types = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
let attributes = type.GetCustomAttributes(typeof(TEnumType), true)
where (attributes.Any()) && (typeof(TSubType).IsAssignableFrom(type)) && (type.IsClass)
select
new
{
dietEnum = (Enum)((TEnumType)attributes.First()).Something,
dietType = type
}).ToDictionary(x => x.dietEnum, x => x.dietType);
}
public T CreateInstance(Enum id, params object[] param)
{
return (T)Activator.CreateInstance(types[id], param);
}
}
class DietFactory : AbstractFactory<Diet>
{
public DietFactory()
{
Register<DietTypeAttribute, Diet>();
}
}
And testing...
void Main()
{
AbstractFactory<Diet> factory = new DietFactory();
Diet diet = factory.CreateInstance(DietType.Carnivore);
//diet is a 'Carnivore'
diet = factory.CreateInstance(DietType.Herbivore);
//diet is a 'Herbivore'
}
Edit: You don't actually need the template types for this
abstract class AbstractFactory<T> where T : class
{
protected Dictionary<Enum, Type> types;
protected AbstractFactory()
{
types = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
let attributes = type.GetCustomAttributes(typeof(FactoryAttribute), true)
where (attributes.Any()) && (typeof(T).IsAssignableFrom(type)) && (type.IsClass)
select
new
{
dietEnum = (Enum)((FactoryAttribute)attributes.First()).Something,
dietType = type
}).ToDictionary(x => x.dietEnum, x => x.dietType);
}
public T CreateInstance(Enum id, params object[] param)
{
return (T)Activator.CreateInstance(types[id], param);
}
}
And your factory is simply:
class DietFactory : AbstractFactory<Diet>
{
public DietFactory()
{
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.