I have 1 interface:
public interface ISummary
{
int EventId {get; set;}
}
And many concrete classes that implement this interface:
public class EmployeeSummary : ISummary
{
public int EventId {get; set;},
public int TotalUniqueCount {get; set;}
public int Location {get; set;}
}
public class CarSummary : ISummary
{
public int EventId {get; set;}
public int TotalMiles {get; set;}
public int TotalHours {get; set;}
}
etc....
The only shared property is the EventId
. Is there a way to have 1 factory method that creates all of these summary objects? I want 1 entry point which decides which objects to create.
So something like:
public ISummary CreateSummary(ConcreteObjectType with properties)
{
if EmployeeSummary
--Call this method to create and return EmployeeSummary
if CarSummary
--Call this method create and return CarSummary
}
I want all calls within other classes to call this method rather than creating the objects themselves.
The part I am struggling with is how do I pass the properties to assign to the objects to this CreateSummary
method since all the properties on the objects will be different?
I am open to changing the objects at this point at well if there is a better design pattern I should be using here.
Well, that's exactly why Factory Method pattern exists :
public class SummaryFactory
{
// new instance with values assigned by action delegate or default
public T Create<T>(Action<T> action = null) where T : ISummary, new()
{
var result = new T();
action?.Invoke(result);
return result;
}
// with object to assign value from (map)
public T Create<T>(object map) where T : ISummary, new()
{
var result = new T();
PropertyInfo[] props = map.GetType().GetProperties();
PropertyInfo[] tProps = typeof(T).GetProperties();
foreach (var prop in props)
{
var upperPropName = prop.Name.ToUpper();
var foundProperty = tProps.FirstOrDefault(p => p.Name.ToUpper() == upperPropName);
foundProperty?.SetValue(result, prop.GetValue(map));
}
return result;
}
// new instance without generic parameters
public object Create(Type type)
{
var instance = Activator.CreateInstance(type);
// add some other logic that changes instance
return instance;
}
}
And now you can use this factory :
var factory = new SummaryFactory();
var carSummary = factory.Create<CarSummary>();
var carSummary2 = factory.Create<CarSummary>(car => { car.TotalMiles = 50; });
var carSummary3 = factory.Create<CarSummary>(new { TotalMiles = 50 });
var employeeSummary = factory.Create(typeof(EmployeeSummary));