2

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

Есть еще один небольшой прыжок здесь, я пропал без вести.

ответ

1

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

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

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

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

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

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

Кроме того, вместо того, чтобы выше, может быть, вы могли бы изменить его следующим образом:

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

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

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

+0

Я вроде как думает, что фабрика несет ответственность за правильное отображение? так почему бы не словарь удерживать сопоставления, которые заполняются при инициализации фабрики? – NotMyself

+0

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

2

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

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

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

+0

Вы следите за мной в порядке .. это то, что я ищу. Но ISpecification.GetUpdate() пахнет мне .. Я ищу способ SRP для выполнения этого, возможно, ISpecificationCommandMapper? – NotMyself

+0

Не знаете, почему это должно пахнуть, если это очень плавное (много людей, пишущих на них), сохраняя спецификации и обновления вместе. Однако с небольшим набором, тогда их объединение может быть лучше. Существенным фактором является то, сколько логики для отображения. Как всегда, контекст важен. – Richard