Профилировщик скорости - абстрактный метод или переключатель на основе типа аргумента - PullRequest
0 голосов
/ 25 февраля 2012

Детали проблемы. Мне нужно создать структуру для выполнения различных проверок, таких как: - Дата A между датами B и C? - Целое число A больше, чем целое число B и меньше, чем целое число C? и т.п. До сих пор я думаю о двух возможных реализациях, подробности ниже.

Impl1 - использование одного класса для выполнения проверок на основе типа проверки.

import java.sql.Time;
import java.util.Date;

public class SearchManager {

    public final static int SEARCH_TYPE_DATE = 0;
    public final static int SEARCH_TYPE_INT = 1;
    public final static int SEARCH_TYPE_STRING = 2;
    public final static int SEARCH_TYPE_TIME = 3;

    private final int searchType;

    public SearchManager(int searchType) {
        this.searchType = searchType;
    }

    public final boolean doCompare(Object minValue, Object maxValue, Object toBeCompared) {
        switch (this.searchType) {
            case SEARCH_TYPE_DATE: {
                return compareDates((Date) minValue, (Date) maxValue, (Date) toBeCompared);
            }
            case SEARCH_TYPE_INT: {
                return compareIntegers((Integer) minValue, (Integer) maxValue, (Integer) toBeCompared);
            }
            case SEARCH_TYPE_STRING: {
                return compareStrings(String.valueOf(minValue), String.valueOf(maxValue), String.valueOf(toBeCompared));
            }
            case SEARCH_TYPE_TIME: {
                return compareTimes((Time) minValue, (Time) maxValue, (Time) toBeCompared);
            }
            default:
                return false;
        }
    }

    private boolean compareDates(Date min, Date max, Date toBeCompared) {
        boolean result = false;
        // actual comparison
        return result;
    }

    private boolean compareIntegers(Integer min, Integer max, Integer toBeCompared) {
        boolean result = false;
        // actual comparison
        return result;
    }

    private boolean compareStrings(String min, String max, String toBeCompared) {
        boolean result = false;
        // actual comparison
        return result;
    }

    private boolean compareTimes(Time min, Time max, Time toBeComparedDate) {
        boolean result = false;
        // actual comparison
        return result;
    }
}

Impl2 - использование абстрактного класса или интерфейса и реализация метода сравнения для каждого типа поиска.

public abstract class AbstractSearch {

public final static int SEARCH_TYPE_DATE = 0;
public final static int SEARCH_TYPE_INT = 1;
public final static int SEARCH_TYPE_STRING = 2;
public final static int SEARCH_TYPE_TIME = 3;

public AbstractSearch() {
    super(); //just for fun
}

protected abstract boolean doCompare(Object minValue, Object maxValue, Object toBeComparedValue);

}

Теперь, в этом примере, для X различных типов поиска, как вы можете себе представить, будут созданы X реализации AbstractSearch.

Просто представьте, что класс AbstractSearch из 2-й реализации должен будет выполнять дополнительные задачи, отличные от метода doCompare(..), и поэтому интерфейс не является моим первым кандидатом на это решение, и писать что-то вроде

public abstract class AbstractSearch implements Searcheable

не сильно мне поможет, так как AbstractSearch или SearchManager будут обрабатывать ВСЕ сравнения, и, если потребуется новый тип сравнения, будет объявлена ​​дополнительная реализация типа / подкласса для соответствующих суперклассов из Impl1. или Impl2.

Мой вопрос о том, какая реализация быстрее? И это очень важно, поскольку процесс сравнения будет вызываться в циклах, содержащих тысячи элементов. Спасибо за чтение / ответ на мой вопрос.

EDIT1 : Также имейте в виду тот факт, что minValue и maxValue будут извлечены из классов, расширяющих AbstractSearch, для второго примера, или классов, расширяющих SearchManager, как для 1-й пример. Эти реализации на самом деле будут графическими компонентами, позволяющими пользователю вводить минимальное и максимальное значения, а затем эти значения будут сравниваться в цикле с некоторым свойством bean-компонента объектов, отображаемых в таблице.

EDIT2 : я делаю некоторые тесты, с использованием фиктивных реализаций (я просто хочу сравнить время вызова метода и время выполнения коммутатора). Результаты удивительны:

  • Использование AbstractSearch (500k циклов): -0,047 секунд
  • Использование SearchManager (500 000 циклов): -0,422 секунды

Имея эти результаты, можно предположить, что использование наследования намного быстрее, чем использование переключателя (или, что еще хуже, теста if-else)?

Ответы [ 4 ]

1 голос
/ 25 февраля 2012

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

public final static boolean doCompare(Date min, Date max, Date toCompare) {
  // ...
}
public final static boolean doCompare(int min, int max, int toCompare) {
  // ...
}
// ...and so on

Во время компиляции компилятор сгенерирует прямой вызов соответствующего метода, основываясь на типах, которые вы передаете. (Если вы передаете объектные ссылки, которые могут указывать на экземпляр любого из 4 типов, это не сработает.)

Если сравниваемые значения int s, передача их методу, принимающему Object аргументы, потребует упаковки и распаковки, что увеличивает накладные расходы.

Если производительность действительно важна, я рекомендую вам использовать static методы, так как они немного быстрее во многих реализациях Java.

Кроме того, вместо использования compareTo вы, вероятно, сможете немного повысить производительность, используя собственный встроенный код для сравнения.

РЕДАКТИРОВАТЬ: Вы сказали в отредактированном вопросе, что min и max будут фактически переданы подклассом из SearchManager. В этом случае я бы сделал SearchManager abstract и поместил бы разные реализации doCompare в каждом подклассе SearchManager. То, что я сказал о static методах, не будет работать в этом случае.

1 голос
/ 25 февраля 2012

Я думаю, что лучшей идеей было бы объединить обе идеи (и сделать их более безопасными с точки зрения типов) и использовать тот факт, что все типы, которые вы предоставляете в своем примере (Date, Time, String и Integer) сопоставимы

public final <A> boolean doCompare (Comparable<A> min, Comparable<A> max, A target)
{
   return (min.compareTo(target) < 0) && (max.compareTo(target) > 0)
}

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

0 голосов
/ 25 февраля 2012

Веселый вопрос!Почему бы вам не сравнить свои две реализации?

0 голосов
/ 25 февраля 2012

Это просто то, что вы можете сделать со сравнением?(Похоже на это.) Является ли этот метод по сути одинаковым для всех трех реализаций?

Если это так, просто напишите

static <T extends Comparable<T>> boolean doCompare(T min, T max, T toCompare) {
  // impl here
}
...