Уменьшите отпечаток памяти, заменив анонимный класс на синглтон. Но нужно реорганизовать дизайн больше - PullRequest
5 голосов
/ 03 июня 2011

Итак, у меня есть этот метод, который выполняется многократно

public static boolean isReady(String dirPath, int numPdfInPrintJob){
    File dir = new File(dirPath);
    String[] fileList = dir.list(new FilenameFilter(){
        public boolean accept(File file, String filename) {
            return (filename.toLowerCase().endsWith(".pdf"));
        }
    });
    if(fileList.length >= numPdfInPrintJob) return true;
    else return false;  
}

Этот метод использует anonymous class, который будет каждый раз вызывать новый экземпляр FilenameFilter, и я часто вызываю этот метод.Поэтому я хочу превратить это anonymous class в singleton.Поэтому моя первоначальная мысль состоит в том, чтобы создать новый класс singleton, который будет выглядеть следующим образом:

public class PdfFileNameFilter implements FilenameFilter{
    private PdfFileNameFilter(){} //non-instantible

    //guarantee to only have one instance at all time
    public static final PdfFileNameFilter INSTANCE = new PdfFileNameFilter();

    public boolean accept(File dir, String name) {
        return (name.toLowerCase().endsWith(".pdf"));
    }
}

Могу ли я еще немного реорганизовать это?Мне также нужно сделать ZipFileNameFilter, и, возможно, много разных фильтров расширений файлов.Не хочу создавать класс для каждого фильтра.Мне нужно немного реорганизовать этот дизайн.Может быть interface встанет где-то здесь.

Ответы [ 6 ]

6 голосов
/ 03 июня 2011

Если все, что вы хотели сделать, это уменьшить использование памяти, то вы могли бы сделать

private static final FilenameFilter PDF_FILES = new FilenameFilter(){
    public boolean accept(File file, String filename) {
        return (filename.toLowerCase().endsWith(".pdf"));
    }
}

Если вы хотите создать синглтон, самый простой способ -

public enum PdfFileNameFilter implements FilenameFilter {
    INSTANCE;

    public boolean accept(File dir, String name) {
        return (name.toLowerCase().endsWith(".pdf"));
    }
}
4 голосов
/ 03 июня 2011

Мне кажется, проще использовать существующий анонимный класс и создать один экземпляр, который используют все вызовы методов.

private static final FilenameFilter PDF_FILTER = new FilenameFilter() {
    public boolean accept(File file, String filename) {
        return (filename.toLowerCase().endsWith(".pdf"));
    }
}

public static boolean isReady(String dirPath, int numPdfInPrintJob){
    File dir = new File(dirPath);
    String[] fileList = dir.list(pdfFilter);
    if(fileList.length >= numPdfInPrintJob) return true;
    else return false;  
}

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

3 голосов
/ 03 июня 2011

Вы можете использовать enum для этого:

public enum ExtensionFilter implements FilenameFilter {
    PDF(".pdf"),
    ZIP(".zip");

    private final String extension;

    private ExtensionFilter(String extension) {
        this.extension = extension;
    }

    @Override
    public boolean accept(File dir, String name) {
        return (name.toLowerCase().endsWith(extension));
    }
}

Теперь вы сможете использовать его следующим образом:

dir.list(ExtensionFilter.PDF)

Вы также можете перебирать их, если выneed:

for ( FilenameFilter fileNameFilter : ExtensionFilter.values() ) {
    ....
}

Вы также можете использовать vararg в качестве аргумента конструктора, чтобы разрешить несколько расширений для одного фильтра, и использовать имя константы в качестве значения по умолчанию, чтобы упростить его использование:

public enum ExtensionFilter implements FilenameFilter {
    PDF,
    ZIP(".zip", ".jar", ".war", ".ear");

    private final String[] extensions;

    private ExtensionFilter(String... extensions) {
        if (extensions.length == 0) {
            extensions = new String[] {"." + name().toLowerCase()};
        }
        this.extensions = extensions;
    }

    @Override
    public boolean accept(File dir, String name) {
        for (String extension : extensions) {
            if (name.toLowerCase().endsWith(extension)) {
                return true;
            }
        }
        return false;
    }
}
1 голос
/ 03 июня 2011

Для интереса, эта альтернативная реализация accept будет работать намного быстрее в тесте производительности.Он не создает новые объекты с состоянием и не переносит другие издержки String.toLowerCase, что не требуется для вашего случая.

  public boolean accept(File file, String filename) {
    int offset = s.length() - 4;
    if (offset >= 0) {
      if (s.charAt(offset) == '.') {
        offset += 1;
        if (s.regionMatches(offset, "pdf", 0, 3)) {
          return true;
        } else if (s.regionMatches(offset, "PDF", 0, 3)) { 
          return true;
        }
      }
    }
    return false;
  }

Если это была горячая точка выполнения, и вы искали оптимизацию, что-то подобноепоможет.

1 голос
/ 03 июня 2011

Могу ли я сделать рефакторинг немного больше?

Да, да, вы можете.

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

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

TDD также является лучшим способом безопасного рефакторинга. Если у вас есть тесты, показывающие, какой код вам на самом деле нужен, много лишних вещей исчезнет, ​​если таковые имеются. А с помощью комплексного набора тестов вы можете без всяких колебаний выполнить рефакторинг, поскольку вы знаете, работают ли ваши изменения или нет, в зависимости от того, продолжают ли ваши тесты проходить.

1 голос
/ 03 июня 2011

вы можете отойти от полного синглтона и использовать личное поле для установки расширения

public class ExtensionFileNameFilter implements FilenameFilter{
    private String extension;
    private ExtensionFileNameFilter (String extension){this.extension=extension;} 

    public static final ExtensionFileNameFilter PDFINSTANCE = new ExtensionFileNameFilter (".pdf");
    public static final ExtensionFileNameFilter ZIPINSTANCE = new ExtensionFileNameFilter (".zip");
    //add instances as you need

    public boolean accept(File dir, String name) {
        return (name.toLowerCase().endsWith(extension));
    }
}
...