Реализация фабрики, которая использует спецификации для определения того, какой тип объекта создавать
-
05-09-2019 - |
Вопрос
В основном это мысленный эксперимент.Итак, это все пример кода.Моя цель состояла в том, чтобы использовать шаблон спецификации для устранения гигантских блоков условного кода внутри фабрики.Итак, с этим примером у меня есть объект StatusData, для которого я хочу получить реализацию IStatusUpdate, подходящую для него.
У меня есть следующий набор тестов:
[TestMethod]
public void Factory_Interface_Should_Return_IStatusUpdate()
{
var factory = MockRepository.GenerateMock<IUpdateFactory<StatusData>>();
var obj = MockRepository.GenerateStub<IStatusUpdate>();
var data = new StatusData();
factory.Stub(x => x.Get(data)).Return(obj);
var item = factory.Get(data);
Assert.IsInstanceOfType(item, typeof(IStatusUpdate));
}
[TestMethod]
public void StatusUpdateFactory_Should_Return_IStatusUpdate()
{
var factory = new StatusUpdateFactory();
var data = new StatusData();
var item = factory.Get(data);
Assert.IsInstanceOfType(item, typeof(IStatusUpdate));
}
[TestMethod]
public void StatusUpdateFactory_Should_Return_NewStatusUpdate_When_Status_Is_New()
{
var data = new StatusData(Status.New);
var factory = new StatusUpdateFactory();
var item = factory.Get(data);
Assert.IsInstanceOfType(item, typeof(NewStatusUpdate));
}
Моя заводская реализация пока выглядит следующим образом:
public class StatusUpdateFactory:IUpdateFactory<StatusData>
{
public IStatusUpdate Get(StatusData item)
{
IList<ISpecification<StatusData>> specs = GetSpecifications();
foreach (var spec in specs)
{
if (spec.IsSatisfiedBy(item))
//how do I do this?
return new NewStatusUpdate();
}
return null;
}
private IList<ISpecification<StatusData>> GetSpecifications()
{
var returnList = new List<ISpecification<StatusData>>();
var specTypes = this.GetType().Assembly.GetTypes()
.Where(z => z.IsInstanceOfType(typeof(ISpecification<StatusData>)))
.ToList();
specTypes.ForEach(x => returnList.Add(Activator.CreateInstance(x) as ISpecification<StatusData>));
return returnList;
}
}
Где я падаю, так это после того, как я обнаружил спецификацию, которая удовлетворяется объектом status, как мне сопоставить эту спецификацию с типом, который реализует IStatusUpdate..Я в тупике.
Кто-то справедливо предположил, что мне нужно сопоставление спецификаций с разработчиками IStatusUpdate.Это сопоставление, по-видимому, является обязанностью фабрики, вычеркивание его из спецификации пахнет нарушением SRP.Я мог бы создать класс Mapper, который несет такую ответственность, но это кажется не очень общим, а также поднимает вопрос, как мне сопоставить mapper со спецификацией.
Здесь мне все еще не хватает одного маленького скачка.
Решение
Итак, я предполагаю, что мы действительно сосредоточились на этом наборе линий:
if (spec.IsSatisfiedBy(item))
return new NewStatusUpdate();
и я предполагаю, что вы спрашиваете, как в данной текущей форме это можно сделать.Кажется, что элемент должен поддерживать, как
interface ISpecSupport<T>
{
bool ItemSpecsContain(ISpecification<T> spec);
}
Затем спецификация.Метод IsSatisfiedBy может использовать этот тип интерфейса и запускать метод.
Другими словами, я предполагаю, что я говорю, что объект должен содержать какое-то описание того, что это такое (в терминах спецификаций).Я предполагаю, что это какой-то список, но я не уверен.Я уверен, что вы, вероятно, думали об этом, поэтому, если вы можете добавить что-нибудь, что было бы полезно.
Кроме того, вместо вышесказанного, возможно, вы могли бы изменить его следующим образом:
if (item.Satisfies(spec))
return new NewStatusUpdate();
Тогда таким образом вам не придется использовать сильно оклеветанный шаблон посетителя (я думаю, это то, что я описывал перед этим).Это более прямолинейно, поскольку кажется, что товару будут принадлежать спецификации, и таким образом вы позволяете товару решать, соответствует ли он спецификации.
Если вы не хотите, чтобы эта логика сохранялась внутри объекта (что я бы понял), И вы используете какой-то пакет свойств (или вы не против отражения), вы могли бы углубиться в детали объекта с помощью независимого средства проверки спецификаций.На самом деле, независимый валидатор, возможно, с самого начала был бы неплохой идеей.Я не совсем уверен, что возможность узнать, соответствует ли спецификация элементу, - это ответственность, которая должна оставаться за отдельной спецификацией.
Другие советы
Если я правильно понял, вы хотите, чтобы, учитывая объект, реализующий ISpecification, вы хотели, чтобы объект, реализующий IStatusUpdate?
В вашем примере ни один из этих типов не определен, поэтому я не знаю, есть ли между ними какая-либо связь, которую вы могли бы использовать.
Но, скорее всего, вам потребуется либо какая-то фабрика для хранения кода, либо спецификация метода.GetUpdate() для создания объекта.