С# factory - это upcast a must?
Требуется ли шаблон С# factory?
Я хочу, чтобы Бог в библиотеке классов G создал Адама в библиотеке классов A, не делая G зависимым от A. Бог производит Адамс для потребления Евой в библиотеке классов E, и это хорошо, чтобы Ева могла знать и зависеть от Адама.
(edit - этот образец продолжает улучшаться и улучшаться:)
Решение, о котором я мог думать, это наличие AdamFactory в A. Таким образом AdamFactory знает Адама и может легко его создать (возможно, просто вызвав конструктор Adam). Бог получает AdamFactory и может заказать его для CreateAdam.
Теперь, поскольку Богу не разрешено знать Адама, AdamFacotry CreateAdam должен вернуть объект, и для этого требуется, чтобы Eve поднял объект, возвращенный AdamFactory, на Адама.
Это будет работать, я думаю. Тем не менее, я чувствую себя неловко из-за кастинга, поскольку это не-нет. Это действительно необходимо?
P.S. - Не богохульство предназначалось, и я извиняюсь, если кому-то было больно. Казалось бы, лучше использовать Бога и Адама вместо Создателя и Создано, потому что два последних слова слишком похожи друг на друга.
Изменить: повторить предложение интерфейса. Предположим, что у Адама есть два метода: ProvideLove, ProvideFood и ProvideProtection (мы держим этот образец kis-safe:). Ева использует Адама для этих двух целей, но, конечно, Бог этого не делает. Итак, зачем предоставлять Богу знание о том, что AdamFactor возвращает то, что реализует IAdam, а не только объект? Я не понимаю!
Изменить: рабочий код (со всеми в той же библиотеке, которую моя цель состоит в том, чтобы разделить на разные библиотеки) выглядит примерно так:
Adam God.LoadAdam(AdamID theAdamID)
var adam = new Adam(theAdamId, this)
Adam.Adam(AdamID theAdamID, God theGod)
_god = theGod
_mind = theGod.LoadMind(theAdamId, this)
Mind God.LoadMind (AdamID theAdamID, Adam theAdam)
var mind = new Mind (theAdam)
var mindId = new minId(theAdamId)
mind.DeserializeFromFile(minId)
Mind.Mind (Adam theAdam)
_adam = theAdam
Ответы
Ответ 1
Я не уверен, что полностью понимаю требования, но вот предложение:
//in assembly G
public abstract class HumanFactory<T>
{
public abstract T CreateHuman();
}
//in assembly A
public class Adam { }
//in assembly A
public class AdamFactory : HumanFactory<Adam>
{
public override Adam CreateHuman()
{
return new Adam();
}
}
//in assembly G
public class God
{
public T Create<T>(HumanFactory<T> factory)
{
return factory.CreateHuman();
}
}
и использование:
//Somewhere in assembly E
Adam adam = new God().Create(new AdamFactory());
Ответ 2
Как насчет использования интерфейсов, чтобы Бог знал IAdam, или что-то вроде IHuman?
Ответ 3
Я думаю, вы могли бы использовать инъекцию зависимости. Попробуйте использовать контейнер с инверсией контроля (IoC), например Unity 2, StructureMap, или Замок Виндзора.
Ответ 4
Вы описываете абстрактный шаблон factory, хотя "детские" заводы (например, AdamFactory) обычно имеют что-то общее, поэтому вы 'd ожидать, что они будут создавать нечто большее, чем общий интерфейс, а не просто объект (см. ответ Davide)
Вы правы, чтобы беспокоиться о актерском составе, поскольку это свяжет Еву с реализацией Адама, которая побеждает цель factory (если вы действительно не используете его как строителя).
Вопрос в том, зачем вам нужен класс Бога?
Ответ 5
Хорошо, если Бог является библиотекой классов персистентности, как вы упомянули в комментарии, тогда это не должно влиять на дизайн класса остальной системы.
Итак, я бы не добавил лишние интерфейсы. Это нормально возвращать объект из десериализатора и затем вниз (например, BinaryFormatter, XmlSerializer).
Лучший способ - сделать ваш десериализатор общим.
Ответ 6
ОК, а как насчет разбрызгивания в некоторых дженериках здесь?
Пусть говорят, что Бог может принять Фабрики любого типа T, которые придерживаются следующего интерфейса:
interface IFactory {
Type CreatedType { get; }
object Create();
}
Абстрактный класс для реализации этого может выглядеть следующим образом:
abstract class AbstractFactory<T> : IFactory {
public Type CreatedType { get { return typeof(T); }
public virtual object Create() {
return innerCreate();
}
protected abstract override T innerCreate();
}
Теперь вы можете регистрировать фабрики с Богом:
God.RegisterFactory(new AdamFactory());
AdamFactory наследует от AbstractFactory<Adam>
Бог хранит свои фабрики в словаре, где ключ - это тип, возвращаемый интерфейсом IFactory
Теперь метод Create выглядит следующим образом:
God.Create<Adam>();
Бог заглядывает в свои фабрики, видит, что существует один тип type (T) общего метода, извлекает factory, вызывает создание и downcasts в T.
Как вы думаете?