Используя фабричный шаблон и отражение (как описано в этом блоге po st), вы получите:
static void Main(string[] args)
{
ReportFactory<Report> factory = new ReportFactory<Report>();
Report r1 = factory.CreateObject("LandscapeReport");
Report r2 = factory.CreateObject("PortraitReport");
Console.WriteLine(r1.WhoAmI());
Console.WriteLine(r2.WhoAmI());
}
Что бы вывести "Пейзаж" и "Портрет", соответственно.
Конечно, для сантехники вам нужен интерфейс, на котором основаны все ваши отчеты (который, я полагаю, у вас уже есть).
Для этого примера:
public interface Report
{
string WhoAmI();
}
И две реализации:
public class PortraitReport : Report
{
public string WhoAmI()
{
return "Portrait";
}
}
public class LandscapeReport : Report
{
public string WhoAmI()
{
return "Landscape";
}
}
Секрет кроется в ReportFactory, который использует Reflection, чтобы увидеть, какие другие классы основаны на Report, и автоматически зарегистрировать их для использования, что я считаю довольно круто:
public class ReportFactory<Report>
{
private Dictionary<string, Type> reportMap = new Dictionary<string, Type>();
public ReportFactory()
{
Type[] reportTypes = Assembly.GetAssembly(typeof(Report)).GetTypes();
foreach (Type reportType in reportTypes)
{
if (!typeof(Report).IsAssignableFrom(reportType) || reportType == typeof(Report))
{
// reportType is not derived from Report
continue;
}
reportMap.Add(reportType.Name, reportType);
}
}
public Report CreateObject(string ReportName, params object[] args)
{
return (Report)Activator.CreateInstance(reportMap[ReportName], args);
}
}
Так что теперь все, что вам нужно сделать, это просто добавить любые новые реализации Report в вашу сборку, и они будут доступны на заводе без дополнительного кодирования или изменения других файлов кода.