Прежде всего, непонятно, почему вы создаете классы, полученные из вашего общего класса, а не напрямую используя общий класс. Также не понятно, почему вам нужен завод, а не просто создавать любые классы, которые вам нужны напрямую. Эти шаблоны важны и полезны, часто единственный способ решить определенные проблемы, но они не соответствуют требованиям . У вас должны быть веские причины для их реализации.
Я предполагаю, что у вас действительно есть веские причины, по которым вы ушли из-за краткости.
Пункт использования шаблона фабрики заключается в том, чтобы часть кода создавала экземпляр правильного класса без этого кода, зная правильный класс. Обратите внимание, что в вашем примере это разделение отсутствует: тот, кто звонит MyClassFactory.CreateMyClass<T>()
должен знать правильный класс, так как этот код должен передать тип как общий параметр, который определяет правильный класс. Если я знаю достаточно, чтобы позвонить CreateMyClass<int>()
, то я достаточно знаю, чтобы позвонить new MyDerivedIntClass()
.
Существует два основных способа реализации шаблона фабрики: статические функции и заводские классы.
С обоими методами, вы будете нуждаться в абстрактный базовый класс или интерфейс «под» дженериков:
public interface IMyInterface
{
string Foo();
}
public abstract class MyGenericBaseClass<T> : IMyInterface
{
// ...
abstract /* or virtual */ string Foo();
}
Используя статическую функцию, вам потребуется тип делегата, определенный где (класс сфера опущен) :
// note: I'm not sure this is the correct syntax, but I think I'm in the ballpark
delegate IMyInterface MyInterfaceFactory();
и классы могут реализовать их, чтобы вернуть правильный тип.
public sealed class MyDerivedIntClass : MyGenericBaseClass<int>
{
// ...
static IMyInterface CreateObject() { return new MyDerivedIntClass(); }
}
public sealed class MyDerivedStringClass : MyGenericBaseClass<string>
{
// ...
static IMyInterface CreateObject() { return new MyDerivedStringClass(); }
}
Вы передаете статическую функцию к функции, который создает объект:
// ... somewhere else in the code ...
// create a IMyInterface object using a factory method and do something with it
void Bar (MyInterfaceFactory factory)
{
IMyInterface mySomething = factory();
string foo = mySomething.Foo();
}
// ... somewhere else in the code ...
void FooBarAnInt()
{
Bar (MyDerivedIntClass.CreateObject);
}
Второй способ заключается в использовании фабричных классов:
public interface IMyInterfaceFactory
{
IMyInterface CreateObject();
}
public class MyDerivedIntFactory : IMyInterfaceFactory
{
public IMyInterface CreateObject() { return new MyDerivedIntClass(); }
}
public class MyDerivedStringFactory : IMyInterfaceFactory
{
public IMyInterface CreateObject() { return new MyDerivedStringClass(); }
}
// ... somewhere else ...
// create a IMyInterface object using a factory class and do something with it
void Bar (IMyInterfaceFactory factory)
{
IMyInterface mySomething = factory.CreateObject();
string foo = mySomething.Foo();
}
// ... somewhere else in the code ...
void FooBarAnInt()
{
Bar (new MyDerivedIntFactory());
}
Обратите внимание, что вы можете (и, вероятно, должен) также сделать заводские классы одиночными, но это другая проблема. Кроме того, вы можете использовать абстрактный базовый класс вместо интерфейса; вам нужно будет добавить abstract
(или virtual
) и override
при необходимости.
По существу, кто-то, где-то, должен знать правильный тип объекта для создания экземпляра. Точка фабричных объектов заключается не в том, чтобы полностью отвлечь это знание, а до отделить знание того, какой тип объекта создать из кода, который фактически создает объект. Если вам не требуется такое разделение, заводская схема не особенно полезна.
«Отойдите», что? –
Я не понимаю, почему вы используете общий завод, если фактические типы, которые вы используете, вообще не являются общими. Я думаю, вы должны пересмотреть свой дизайн. – Joren