Написание метода, основанного на значении перечисления, без запаха кода - PullRequest
3 голосов
/ 28 ноября 2008

Представьте, что у меня есть документ (слово-документ).

У меня есть перечисление, которое будет указывать, как извлечь данные из документа. Поэтому, если я хочу просто текст, изображения или оба (3 члена перечисления).

У меня есть инструкция case, основанная на этом перечислении, но без запаха кода, как я могу написать код, который не слишком повторяется? Для каждого условия в коммутаторе, должен ли я иметь отдельный метод (самый простой способ) или метод, принимающий paremeter (например, значение перечисления), и затем использовать операторы if, чтобы сказать, что (xyz) делает abc, и так на.

Или есть более быстрый и эффективный способ?

Ответы [ 7 ]

7 голосов
/ 28 ноября 2008

Я бы использовал шаблон Стратегии в сочетании с фабрикой, чтобы создать соответствующую стратегию, основанную на значении перечисления. РЕДАКТИРОВАТЬ Как уже отмечали другие, вы также можете определить правильную стратегию с помощью карты. Фабрика - мой выбор, потому что она только заключает в себе логику и не требует хранения данных.

public interface IExtractionStrategy
{
    object Extract( Document doc );  // or what ever result is best
}

public class TextExtractionStrategy : IExtractionStrategy
{
    public object Extract( Document doc )
    {
     .... algorithm for extracting text...
    }
}

public class ImageExtractionStrategy : IExtractionStrategy
{
    public object Extract( Document doc )
    {
     .... algorithm for extracting images...
    }
}


public static class StrategyFactory
{
     IExtractionStrategy GetStrategy( ExtractionEnum strategyType )
     {
         switch (strategyType)
         {
             case ExtractionEnum.Text:
                 return new TextExtractionStrategy();
                 break;
             case ExtractionEnum.Image:
                 return new ImageExtractionStrategy();
                 break;

             ...
         }
     }
}
3 голосов
/ 28 ноября 2008

Поскольку трудно дать общее утверждение, не зная вашего точного кода, я могу только рекомендовать вам прочитать эту статью:

Назад к основам - жизнь после If, For и Switch - как напоминание о структурах данных Скотт Хансельман.

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

1 голос
/ 28 ноября 2008

Если вы используете перечисления Java, вы можете использовать тот факт, что они на самом деле являются объектами:

enum ExtractionEnum {
    IMAGE {
        public byte[] extract(InputStream is) { ... }
    },

    TEXT {
        public byte[] extract(InputStream is) { ... }
    };

    public abstract byte[] extract(InputStream is);
}

// ...
public void doSomething(ExtractionEnum type) {
    byte[] data = type.extract(getInputStream());
    ...
}

Я не уверен, что мне это нравится больше, чем шаблон стратегии или добрый 'switch / case, но это работает.

1 голос
/ 28 ноября 2008

Я бы сделал (псевдокод):


switch(enum)
   case images:
       extractImages();
       break;
   case text:
       extractText();
       break;
   case both:
        extractImages();
        extractText();
        break;
1 голос
/ 28 ноября 2008

Сколько классов нужно, чтобы заменить лампочку?

Возможно, это просто различие в терминологии, но мне кажется, что это простой случай необходимости таблицы отправки:

use constant EXTRACT_TEXT => 1, EXTRACT_IMAGES => 2, EXTRACT_BOTH => 3;
my %extractor = (
    (EXTRACT_TEXT) => \&extract_text,
    (EXTRACT_IMAGES) => \&extract_images,
    (EXTRACT_BOTH) => \&extract_both,
);
...
die "no extractor found for $enum_value" if ! $extractor{ $enum_value };
$extractor{ $enum_value }->( $document_info );
1 голос
/ 28 ноября 2008

Используйте шаблон стратегии , чтобы отделить метод обработки данных от его выбора.

Затем можно использовать прямую Map<Enum, Strategy> для хранения отношения от перечисления к стратегии извлечения или даже для каждого экземпляра перечисления содержать ссылку на свою собственную стратегию.

0 голосов
/ 28 ноября 2008

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

...