Предварительная версия Java 8 большое компараторы реализации


Ищу критику по моей реализации перечня стран, которая предлагает множество способов, чтобы отсортировать его в полезный и простой способ для клиента. Главная забота о дизайне перечисление, которое содержит компараторы и как они предоставляются клиенту (в данном случае класс AlliancesExample). Подробнее об этом в комментарии код.

Я не могу использовать Java 8, так что, хотя я знаю, что все мои компараторы признать лямбда-выражение, я не могу их использовать.

Любые комментарии или предложения относительно моего подхода, стиля кодирования, соглашений, и т. д. будет принята с благодарностью! Спасибо заранее.

public enum Continent {
    ASIA("Asia"),
    AFRICA("Africa"),
    NORTH_AMERICA("North America"),
    SOUTH_AMERICA("South America"),
    ANTARCTICA("Antarctica"),
    EUROPE("Europe"),
    AUSTRALIA("Australia");

    private final String name;

    Continent(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return this.name;
    }
}

import java.util.Comparator;

// Country implements Comparable just in case we want an ordered set of countries
// The comparison is made on ccTLD

public class Country implements Comparable<Country> {
    private final String ccTLD; //UNIQUE, like a Primary Key
    private final String name;
    private final Continent continent;
    private int population;
    private int sizeSquareKiloMeters;

    public Country(String ccTLD, String name, Continent continent, int population, int sizeSquareKiloMeters) {
        this.ccTLD = ccTLD;
        this.name = name;
        this.continent = continent;
        this.population = population;
        this.sizeSquareKiloMeters = sizeSquareKiloMeters;
    }

    //Here is one issue, I offer a dummy constructor to search by ccTLD a list of countries
    public Country(String ccTLD) {
        this.ccTLD = ccTLD;
        this.name = null;
        this.continent = null;
        this.population = 0;
        this.sizeSquareKiloMeters = 0;
    }

    //Its own public enum or inner enum?
    public enum SortingOrder {
        CCTLD(new Comparator<Country>() {
            @Override
            public int compare(Country o1, Country o2) {
                return o1.getCcTLD().compareTo(o2.getCcTLD());
            }
        }),
        NAME(new Comparator<Country>() {
            @Override
            public int compare(Country o1, Country o2) {
                return o1.name.compareTo(o2.getName());
            }
        }),
        CONTINENT(new Comparator<Country>() {
            @Override
            public int compare(Country o1, Country o2) {
                if (o1.getContinent().equals(o2.getContinent())) {
                    return o1.getCcTLD().compareTo(o2.getCcTLD());
                }
                return o1.getContinent().compareTo(o2.getContinent());
            }
        }),
        POPULATION(new Comparator<Country>() {
            @Override
            public int compare(Country o1, Country o2) {
                return Integer.compare(o1.getPopulation(), o2.getPopulation());
            }
        });

        //More comparators

        Comparator<Country> comparator;

        SortingOrder(Comparator<Country> comparator) {

            this.comparator = comparator;

        }

        public Comparator<Country> getComparatorDescending() {
            return comparator.reversed();
        }

        public Comparator<Country> getComparatorAscending() {
            return comparator;
        }
    }

    //Equals only looks ccTLD because is the PK
    //IntelliJ IDEA template
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Country country = (Country) o;

        return ccTLD.equals(country.ccTLD);
    }

    @Override
    public int hashCode() {
        return ccTLD.hashCode();
    }

    @Override
    public int compareTo(Country o) {
        return this.ccTLD.compareTo(o.ccTLD);
    }

    @Override
    public String toString() {
        return "Country{" +
                "ccTLD='" + ccTLD + '\'' +
                ", name='" + name + '\'' +
                ", continent=" + continent +
                ", population=" + population +
                ", sizeSquareKiloMeters=" + sizeSquareKiloMeters +
                '}';
    }

    public String getStringFullData() {
        return getCcTLD() +
                " - " + getName() +
                " - " + getContinent().toString().toUpperCase() +
                "  " + getPopulation() + " pop. " +
                "  " + getSizeSquareKiloMeters() + " km\u00B2";
    }

    public String getCcTLD() {
        return ccTLD;
    }

    public String getName() {
        return name;
    }

    public Continent getContinent() {
        return continent;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    public int getSizeSquareKiloMeters() {
        return sizeSquareKiloMeters;
    }

    public void setSizeSquareKiloMeters(int sizeSquareKiloMeters) {
        this.sizeSquareKiloMeters = sizeSquareKiloMeters;
    }
}

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Alliance {
    private final List<Country> countries = new ArrayList<Country>();
    private final String name;

    public Alliance(String name) {
        this.name = name;
    }

    //It could be a set but I want to sort the list many times and in many ways
    public boolean add(Country c) {
        if (this.contains(c)) {
            return false;
        }
        return this.countries.add(c);
    }

    public boolean remove(Country c) {
        return this.countries.remove(c);
    }

    public boolean contains(Country c) {
        return this.countries.contains(c);
    }

    public Country getByCcTLD(String cctld) {
        for (Country c :
                this.countries) {
            if (c.getCcTLD().equals(cctld)) {
                return c;
            }
        }
        return null;
    }


    //Should I offer the client a generic sort where they pass me the comparator
    //they want to use or encapsulate sort options like this?
    public void sortByName() {
        Collections.sort(this.countries, Country.SortingOrder.NAME.getComparatorAscending());
    }

    public void sortByPopulationDESC() {
        Collections.sort(this.countries, Country.SortingOrder.POPULATION.getComparatorDescending());
    }

    public String getListOfCountries() {
        String output = this.name + "\n";
        for (Country c :
                this.countries) {
            output += c.getStringFullData() + "\n";
        }
        return output;
    }

    public String getName() {
        return name;
    }
}

public class AlliancesExample {
    public static void main(String[] args) {
        Alliance nafta = new Alliance("North American Free Trade Agreement (NAFTA)");
        Country usa = new Country("us",
                "United States of America",
                Continent.NORTH_AMERICA,
                325_719_170,
                9_833_543);
        Country canada = new Country("ca",
                "Canada",
                Continent.NORTH_AMERICA,
                35_151_728,
                9_984_670);
        Country mexico = new Country("mx",
                "Mexico",
                Continent.NORTH_AMERICA,
                123_675_325,
                1_972_550);
        nafta.add(usa);
        nafta.add(canada);
        nafta.add(mexico);
        System.out.println(nafta.getListOfCountries());
        nafta.sortByName();
        System.out.println(nafta.getListOfCountries());
        nafta.sortByPopulationDESC();
        System.out.println(nafta.getListOfCountries());

        Country c = nafta.getByCcTLD("mx");
        if (c != null) {
            System.out.println(c.getName() + " belongs to " + nafta.getName());
            System.out.println("And its data are: " + c.getStringFullData());
        }

    }
}


193
1
задан 2 февраля 2018 в 09:02 Источник Поделиться
Комментарии
1 ответ

Один совет я могу дать, что enumS может реализовывать интерфейсы. Так что вы можете позволить SortingOrder реализации Comparator<Country> как это:

public enum SortingOrder implements Comparator<Country> {
CCTLD {
@Override
public int compare(Country o1, Country o2) {
return o1.getCcTLD().compareTo(o2.getCcTLD());
}
},
NAME {
@Override
public int compare(Country o1, Country o2) {
return o1.name.compareTo(o2.getName());
}
},
CONTINENT {
@Override
public int compare(Country o1, Country o2) {
if (o1.getContinent().equals(o2.getContinent())) {
return o1.getCcTLD().compareTo(o2.getCcTLD());
}
return o1.getContinent().compareTo(o2.getContinent());
}
},
POPULATION {
@Override
public int compare(Country o1, Country o2) {
return Integer.compare(o1.getPopulation(), o2.getPopulation());
}
};

public Comparator<Country> reversed() {
return Collections.reverseOrder(this);
}
}

Это экономит несколько символов в реализации, а также при его использовании:

Collections.sort(this.countries, Country.SortingOrder.NAME);

Collections.sort(this.countries, Country.SortingOrder.POPULATION.reversed());


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


Я не фанат, однако, иметь Country реализации Comparableпоскольку нет никакой объективной заказ CountryС, О чем свидетельствуют различные сортировки заказов. Ваш комментарий говорит, что вы должны это уметь использовать упорядоченные наборы, но те часто позволяют отдельный компаратор использовать любые способы (например TreeSet).

2
ответ дан 4 февраля 2018 в 10:02 Источник Поделиться