Реализация фабрики, которая использует спецификации для определения того, какой тип объекта создавать

StackOverflow https://stackoverflow.com/questions/567868

Вопрос

В основном это мысленный эксперимент.Итак, это все пример кода.Моя цель состояла в том, чтобы использовать шаблон спецификации для устранения гигантских блоков условного кода внутри фабрики.Итак, с этим примером у меня есть объект 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() для создания объекта.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top