Andriy Polishchuk (isorecursive) wrote,
Andriy Polishchuk
isorecursive

Category:

Java: Comparable и Comparator

Пока делал дерево поиска, придумал достаточно гибкий компромисс в использовании сабжа. Допустим, есть некий обобщённый класс, на параметре типа которого должно быть определено отношение порядка (в моём случае это параметр К обобщённого класса BinarySearchTree). Можно не заморачиваться и просто писать констрейнт "K extends Comparable<K>", но это не всегда подходит. Дело в том, что если я или пользователь моего дерева захочет использовать в качестве К не принадлежащий ему класс, не реализующий Comparable, он будет вынужден городить адаптер, а это не очень приятно. Даже если бы этой проблемы не было, меня или пользователя моего класса могла бы не устраивать имеющаяся для К реализация Comparable, и хотелось бы иметь также способ использовать альтернативные. Последнюю проблему решает опциональная параметризация дерева Comparator'ами - например, один из конструкторов дерева будет кушать его параметром - но первая проблема останется, ведь даже если инстанцировать дерево этим конструктором, констрейнт на тип К всё-равно останется, и если класс К не мой, а реализации Comparable там нет - я в пролёте. Очевидное решение - удалить констрейнт совсем, а конструктор с компаратором оставить. Но что, если я не хочу каждый раз скармливать компаратор и в случае, если тип реализует Comparable, хочу иметь возможность использовать его функциональность? На помощь приходят джавовские анонимные классы и паттерн "фабричный метод"!
public class BinarySearchTree<K> {
    
    protected final Comparator<K> comparator;
    
    public BinarySearchTree(Comparator<K> comparator) {
        this.comparator = comparator;        
    }
    
    public static <T extends Comparable<T>> BinarySearchTree<T> ofComparable() {
        return new BinarySearchTree<T>(
            new Comparator<T>() {
                public int compare(T a, T b) {
                    return a.compareTo(b);
                };
            }
        );
    }

  ...
}

Вот так-то! Теперь тип К необременён столь строгим констрейнтом, дерево можно параметризовать произвольными кастомными компараторами, но в случае, если тип К всё-таки Comparable (например, Integer), можно, если хочется, инстацировать дерево вот так вот:
BinarySearchTree<Integer> bst = BinarySearchTree.ofComparable();

А нужный компаратор построится исходя из Comparable сам!
Tags: anonymous class, comparable, comparator, factory method, java
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments