Есть ли элегантный способ реализовать этот шаблонный метод или шаблон, подобный стратегии, в C #? - PullRequest
1 голос
/ 31 мая 2011

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

Позвольте мне придумать простой пример:

Предположим, у вас есть классы / интерфейсы, такие как:

interface IProcessedPhoto { }

interface IPhotoProcessor
{
    IProcessedPhoto Process(byte[] bytes);
    void Alter(IProcessedPhoto processedPhoto);
}

class PhotoProcessedWithAMethod : IProcessedPhoto { }

class PhotoProcessedWithBMethod : IProcessedPhoto { }

class AProcessor : IPhotoProcessor
{ 
    IProcessedPhoto Process(byte[] bytes);  // Returns PhotoProcessedWithAMethod 
    void Alter(IProcessedPhoto processedPhoto)
    {
        var casted = processedPhoto as PhotoProcessedWithAMethod;
        // a "B" would crash here.
    }
}

class BProcessor : IPhotoProcessor
{ 
    IProcessedPhoto Process(byte[] bytes);  // Returns PhotoProcessedWithBMethod  
    void Alter(IProcessedPhoto processedPhoto)
    {
        var casted = processedPhoto as PhotoProcessedWithBMethod;
        // an "A" would crash here.
    }
}

class Algorithm
{
    void DoStuff()
    {
        var processor = ProcessorFactory.CreateProcessor(//stuff);
        var processedPhoto = processor.ProcessPhoto(new byte[100]);
        processor.Alter(processedPhoto);
    }
}

Итак, в основном я хочу, чтобы метод DoStuff () создал один тип процессора изображений и вызвал соответствующий метод Process. Однако, несмотря на то, что предлагает интерфейс, Process работает только с IProcessedPhoto соответствующего типа (фотографии A и B НЕ взаимозаменяемы, они просто имеют похожие имена методов). Мой настоящий код более сложен в том смысле, что каждый процессор имеет несколько классов, специфичных для них и не взаимозаменяемых, но я хочу выполнить тот же набор «логических» операций, как метод шаблона.

var artifactA = processor.DoA();
var artifactB = processor.DoB();
var final = processor.Process(artifactA, artifactB);

Надеюсь, это объясняет.

Ответы [ 3 ]

1 голос
/ 31 мая 2011

Мне хотелось бы поместить метод Alter в интерфейс IProcessedPhoto, а затем вернуть реализацию, которая может корректно изменить обработанную фотографию.Обратите внимание, что вы также можете подключить его к процессору и при необходимости использовать методы из него (не показаны).

public enum PhotoProcessingMethod { A, B }

public interface IProcessedPhoto
{
     void Alter();
}

public AProcessedPhoto : IProcessedPhoto
{
     ...

     public void Alter()
     {
        ... alter an A...
     }
}

public BProcessedPhoto : IProcessedPhoto
{
     ...
     public void Alter()
     {
      ... alter a B...
    }
}

public interface IPhotoProcessor
{
     IProcessedPhoto Process(byte[] bytes, PhotoProcessingMethod method);
}

public class PhotoProcessor : IPhotoProcessor
{
     public IProcessedPhoto Process(byte[] bytes, PhotoProcessingMethod method)
     {
          IProcessedPhoto photo;
          switch (method)
          {
              case PhotoProcessingMethod.A:
                   photo = new AProcessedPhoto(bytes);
                   break;
              case PhotoProcessingMethod.B:
                   photo = new BProcessedPhoto(bytes);
                   break;
          }
          ...

          return photo;
     }
}

Используется как:

var processor = new PhotoProcessor();
var photoA = processor.Process( bytes, PhotoProcessingMethod.A );
photoA.Alter();
1 голос
/ 31 мая 2011

Вы можете использовать дженерики для привязки конкретной реализации IProcessedPhoto к вашим IPhotoProcessor s:

interface IPhotoProcessor<TProcessedPhoto> 
  where TProcessedPhoto: IProcessedPhoto {

  TProcessedPhoto Process(byte[] bytes);
  void Alter(TProcessedPhoto processedPhoto);

}

...

class AProcessor : IPhotoProcessor<PhotoProcessedWithAMethod> { ... }

class BProcessor : IPhotoProcessor<PhotoProcessedWithBMethod> { ... }

Недостатком является то, что вашей фабрике также нужна эта информация:

ProcessorFactory.CreateProcessor<PhotoProcessedWithAMethod>(/*stuff*/); 
1 голос
/ 31 мая 2011

Мне кажется, что ваша IProcessedPhoto / IPhotoProcessor абстракция слишком обобщена, по крайней мере, для целей, которые вы описываете.

Вы можете создать производные интерфейсы для каждого из классов фотографий и процессоров (например, IProcessedPhotoA / IPhotoProcessorA, и то же самое для B) и настроить свой код так, чтобы только те фотографии, которые реализуют требуемый интерфейс (A или B) передаются данному процессору.

Я не уверен, является ли это лучшим решением для всей вашей кодовой базы (чего я не вижу). Мое предложение основано на этой части вашего поста:

Однако, несмотря на то, что предлагает интерфейс, Process работает только с IProcessedPhoto соответствующего типа (фотографии A и B НЕ взаимозаменяемы, они просто имеют похожие имена методов)

Если они не являются взаимозаменяемыми для использования PhotoProcessor, ваш код не должен обрабатывать их как таковые.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...