Рефакторинг кода Java: использование нескольких экземпляров оператора

1

Рассмотрим следующий пример, где классы TextFile, XmlFile, HtmlFile, ShellScriptFile и т.д. - все подклассы класса SimpleFile. Я пишу класс FileOperations, у которого есть метод, который ищет содержимое общего файла в зависимости от его типа.

Ниже приведен пример кода:

public searchFile(SimpleFile targetFile, String searchStr) {
     if (targetPage instanceof HtmlFile) {
         // search html file
     }
     else if (targetPage instanceof TextFile) {
         // search text file
     }
     else if (targetPage instanceof XmlFile) {
         // search xml file
     }
     else if (targetPage instanceof ShellScriptFile) {
         // search shell file
     }   
     ...
}

Эта структура плохо пахнет мне. Я знаю, что это лучший вариант для полиморфизма. Но у меня нет контроля над классом File или его подклассами. Я не могу писать им.

Есть ли еще способ очистить этот беспорядок? Потому что структура if-else будет продолжать увеличиваться по мере добавления поддержки для разных типов файлов.

Иначе, если я застрял с этой структурой, то является instanceof самого быстрого оператора в Java? Каковы его последствия для производительности?

Было бы лучше использовать getClass() или isAssignableFrom() для вышеуказанного случая?

Я ценю ваши комментарии или предложения!

  • 0
    скорость не имеет значения в этой ситуации
  • 0
    Потому что я предполагаю, что «у меня нет контроля над классом файлов или его подклассами»
Показать ещё 1 комментарий
Теги:
polymorphism
operators
refactoring
instanceof

4 ответа

3
Лучший ответ

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

public void searchFile(SimpleFile targetFile , String searchStr) {
     // SimpleFile generalized behavior.
     if (targetPage instanceof HtmlFile) searchFile((HtmlFile)targetFile, searchStr);
     else if (targetPage instanceof TextFile) searchFile((TextFile)targetFile, searchStr);
     else if (targetPage instanceof XmlFile) searchFile((XmlFile)targetFile, searchStr);
     else if (targetPage instanceof ShellScriptFile) searchFile((ShellScriptFile)targetFile, searchStr);
     else System.out.println("Subtype not recognised"); 
}
public void searchFile(HtmlFile targetFile , String searchStr) {
    // HtmlFile specific behavior
}
public void searchFile(TextFile targetFile , String searchStr) {
    // TextFile specific behavior
}
public void searchFile(XmlFile targetFile , String searchStr) {
    // XmlFile specific behavior
}
public void searchFile(ShellScriptFile targetFile , String searchStr) {
    // ShellScript specific behavior
}

В случае нового подкласса SimpleFile он будет по умолчанию SimpleFile версию метода SimpleFile. В случае, если тип не известен во время компиляции (как searchFile() в комментариях), наиболее общий searchFile() может использоваться для проверки и перераспределения объекта соответствующим образом.

Редактирование: как примечание о влиянии производительности на множественное использование instanceof, консенсус, по-видимому, заключается в том, что он не имеет значения и что использование современного экземпляра довольно быстро в любом случае.

  • 1
    Это будет работать, если тип известен во время компиляции.
  • 0
    я согласен, но здесь дело не в этом
Показать ещё 5 комментариев
1

Если вы можете изменить File и его подклассы, вы можете попробовать использовать шаблон посетителя. Поскольку вы не можете, я рекомендую вам консолидировать оператор switch type type в одном методе, так что вам нужно будет только изменить один коммутатор.

public Enum FileHandler {
   HTML(){
      public search(File file, String searchstr){ /* ... */}
      public prettyPrint(File file){ /* ... */}
   },
   XML(){ /* ... */};
   // ... end list of enum implementations

   public static FileHander get(File file){
      // Put your master switch statement here
      if (targetPage instanceof HtmlFile) {
         return HTML;
      }
      else if (targetPage instanceof XmlFile) {
         return XML;
      }
      // ...
   }
}

И ваш код для использования класса enum будет выглядеть примерно так, избегая опасного оператора switch:

public searchFile(SimpleFile targetFile, String searchStr) {
   FileHandler.get(targetFile).search(targetFile, searchStr);
}
0

Моим подходом было бы создать интерфейс FileSearcher с единственным методом, который выполняет бизнес-логику. Создайте одну реализацию этого интерфейса для каждого типа файла. Затем создайте реестр, который сопоставляет подклассы SimpleFile с их соответствующей реализацией FileSearcher. В вашем методе файла поиска, а не в выполнении проверок instanceof, найдите соответствующую реализацию FileSeacher во время выполнения и делегируйте ее.

С этой реализацией вы можете столкнуться с проблемами, когда есть подклассы HtmlFile и т.д., Потому что вам нужно будет сопоставить HtmlFileSearcher со всеми подклассами HtmlFile. В этом случае добавьте еще один метод в FileSearcher именем canHandle(Class<SimpleFile> runtimeClass) который позволяет реализациям FileSearcher сигнализировать, какой класс файлов они понимают. В реестре, а не просматривая его на карте, пройдите через все зарегистрированные FileSearchers.

0

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

пример шаблона-интерпретатора-шаблона, комментарий, если вам нужен пример шаблона цепочки ответственности-дизайна

Клиент:

public Integer wordCountOnPage (Page samplePage) 
{
    ArrayList list = new ArrayList<Page>();
    list.add(new XmlPage());

    list.add(new HtmlPage());

    list.add(new JsonPage());

    for (int index = 0 ; index < list.size(); index ++)

    {
        Page eachPage = (Page) list.get(index); 
        if (eachPage.intercept(samplePage)){
            Integer i = eachPage.wordCountOnPage(samplePage);
        }

    }
    return 1;
}


public class XmlPage implements Page {

@Override
public Boolean intercept(Page page) {
    // TODO Auto-generated method stub
    return page instanceof XmlPage;
}

@Override
public Integer wordCountOnPage(Page page) {
    // TODO Auto-generated method stub
    return null;
}

}

public interface Page {

Boolean intercept(Page page);
Integer wordCountOnPage(Page page);
}
  • 0
    к сожалению, я не могу редактировать базовые или производные классы. Спасибо !!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню