Реализация Фабрики, которая использует Спецификации, чтобы определить, какой тип объекта создать - PullRequest
2 голосов
/ 20 февраля 2009

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

Реализация My Factory до сих пор выглядит следующим образом:

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;

    }
  }

Когда я падаю, когда я обнаружил спецификацию, которая удовлетворяется объектом статуса, как мне сопоставить эту спецификацию с типом, который реализует IStatusUpdate ... Я в замешательстве.

Кто-то справедливо предположил, что мне нужно сопоставление спецификаций с реализациями IStatusUpdate. Похоже, что это отображение является обязанностью завода-изготовителя, вешая его за пределы спецификации, пахнет нарушением SRP. Я мог бы создать класс Mapper, на котором лежит такая ответственность, но который не кажется достаточно общим, а также поднимает вопрос, как мне сопоставить mapper со спецификацией.

Здесь все еще есть один маленький прыжок, которого мне не хватает.

Ответы [ 2 ]

2 голосов
/ 20 февраля 2009

Если я правильно понял, вы хотите, учитывая объект, реализующий спецификацию IS, вы хотите объект, реализующий IStatusUpdate?

В вашем примере ни один из этих типов не определен, поэтому я не знаю, существует ли какая-либо связь между ними, которую вы могли бы использовать.

Но, скорее всего, вам понадобится какая-то фабрика для хранения кода или метод ISpecification.GetUpdate () для создания объекта.

1 голос
/ 20 февраля 2009

Итак, я предполагаю, что мы действительно сосредоточены на этом наборе строк:

if (spec.IsSatisfiedBy(item))
          return new NewStatusUpdate();

и я предполагаю, что вы спрашиваете, как в этой текущей форме это можно сделать. Кажется, что элемент должен поддерживать как

interface ISpecSupport<T>
{
    bool ItemSpecsContain(ISpecification<T> spec);
}

Тогда метод spec.IsSatisfiedBy может взять этот тип интерфейса и запустить метод.

Другими словами, я предполагаю, что говорю, что объект должен нести какое-то описание того, чем он является (в терминах спецификаций). Я предполагаю, что это какой-то список, но я не уверен. Я уверен, что вы, наверное, подумали об этом, так что если вы можете добавить что-нибудь полезное.

Кроме того, вместо вышесказанного, возможно, вы могли бы изменить его так:

if (item.Satisfies(spec))
    return new NewStatusUpdate();

Тогда, таким образом, вам не нужно использовать очень злобный шаблон посетителей (я думаю, это то, что я описывал до этого). Это более прямолинейно, поскольку кажется, что предмету принадлежат спецификации, и таким образом вы позволяете предмету решать, соответствует ли он спецификации.

Если вы не хотите, чтобы эта логика хранилась внутри объекта (что я бы понял) И вы используете какую-то сумку свойств (или вы круты с отражением), вы можете углубиться в детали объекта с помощью независимый валидатор спецификаций. На самом деле, независимый валидатор не может быть плохой идеей для начала. Я не уверен, что способность знать, соответствует ли спецификация предмету, является обязанностью, которая должна оставаться за индивидуальной спецификацией.

...