Статьи

Java Code Challenge: химическое именование символов (часть 2) – решение

Если вам нужно напоминание о том, что участвует в конкурсе, ознакомьтесь со статьей здесь .

Задача на этой неделе была приятной и легкой, предполагая, что вы выполнили  первую  часть задачи, поскольку она в значительной степени использовала тот же код.

Решение действительно зависело от части расширения для первой части, которая дала вам метод, чтобы найти все допустимые символы для элемента. Давайте рассмотрим кодовое решение от Drippel в качестве примера:

for( String chemical : chemicals ){


 List<String> symbols = ChemicalNamer.generateAllSymbols(chemical);

    String toAdd = null;

    for( String symbol : symbols ){

    if( !allSymbols.contains(symbol)){
    toAdd = symbol;
    break;
    }
    }

    if( toAdd == null ){
    // we are done
    System.out.println("stopper:"+ chemical);
    break;
    }

Вся логика поиска допустимых имен помещена в статический класс ChemicalNamer. Возможные решения зациклены, и первое действительное установлено. Этот код, в частности, представляет собой прекрасную возможность для правильного использования функционального кода Java 8 и может быть реорганизован следующим образом:

Optional<String> element = 
  symbols.stream().filter(
  symbol -> !allSymbols.contains(symbol)
   ).findFirst();

if(!element.isPresent()){
System.out.println("stopper:"+ chemical);
break;
}

Как правило, я не фанат предложений break, поэтому использование метода findFirst — хороший способ удалить это.

Выглядит стильно

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

Получение данных в системе

Их решения, как правило, используют файловые входы; каждый имел тенденцию использовать BufferedReader для ввода значений из текстового файла, и мне нравится, что jaumemoral вытащил это в другой класс с TextFileReader, позволяя им тестировать чтение файла отдельно и вообще просто поддерживая хорошее сцепление.

Однако лично я пошел по другому пути. У меня нет планов регулярно повторять это для разных наборов данных, поэтому я просто закодировал список в класс «Данные».

package com.samatkinson;

public class Data {
    public static String[] elements = new String[]{
        "Hydrogen",
        "Helium",
        "Lithium",
        "Beryllium",
        "Boron",
        "Carbon",
        "Nitrogen",
        "Oxygen",
        "Fluorine",
        "Neon",
        "Sodium",
        "Magnesium",
        "Aluminium",
        "Silicon",
        "Phosphorus",
        "Sulfur",
        "Chlorine",
        "Argon",
        "Potassium",
        "Calcium",
        "Scandium",
        "Titanium",
        "Vanadium",
        "Chromium",
        "Manganese",
        "Iron",
        "Cobalt",
        "Nickel",
        "Copper",
        "Zinc",
        "Gallium",
        "Germanium",
        "Arsenic",
        "Selenium",
        "Bromine",
        "Krypton",
        "Rubidium",
        "Strontium",
        "Yttrium",
        "Zirconium",
        "Niobium",
        "Molybdenum",
        "Technetium",
        "Ruthenium",
        "Rhodium",
        "Palladium",
        "Silver",
        "Cadmium",
        "Indium",
        "Tin",
        "Antimony",
        "Tellurium",
        "Iodine",
        "Xenon",
        "Caesium",
        "Barium",
        "Lanthanum",
        "Cerium",
        "Praseodymium",
        "Neodymium",
        "Promethium",
        "Samarium",
        "Europium",
        "Gadolinium",
        "Terbium",
        "Dysprosium",
        "Holmium",
        "Erbium",
        "Thulium",
        "Ytterbium",
        "Lutetium",
        "Hafnium",
        "Tantalum",
        "Tungsten",
        "Rhenium",
        "Osmium",
        "Iridium",
        "Platinum",
        "Gold",
        "Mercury",
        "Thallium",
        "Lead",
        "Bismuth",
        "Polonium",
        "Astatine",
        "Radon",
        "Francium",
        "Radium",
        "Actinium",
        "Thorium",
        "Protactinium",
        "Uranium",
        "Neptunium",
        "Plutonium",
        "Americium",
        "Curium",
        "Berkelium",
        "Californium",
        "Einsteinium",
        "Fermium",
        "Mendelevium",
        "Nobelium",
        "Lawrencium",
        "Rutherfordium",
        "Dubnium",
        "Seaborgium",
        "Bohrium",
        "Hassium",
        "Meitnerium",
        "Darmstadtium",
        "Roentgenium",
        "Copernicium",
        "Ununtrium",
        "Flerovium",
        "Livermorium",
        "Garfieldium",
        "Odium",
        "Nermalium",
        "Pookium",
        "Arbukelium",
        "Binkium",
        "Lizzium",
        "Arlenium",
        "Orsonium",
        "Royium",
        "Wadium",
        "Bookerium",
        "Sheldon",
        "Boium",
        "Lanoline",
        "Leonardium",
        "Donatellium",
        "Michelangelon",
        "Raphaellium",
        "Splinterium",
        "Oneilium",
        "Jonesium",
        "Shredderite",
        "Stockmanium",
        "Beboppium",
        "Rocksteadium",
        "Krangium",
        "Gruffium",
        "Zummium",
        "Grammium",
        "Tummium",
        "Sunnium",
        "Cubbium",
        "Guston",
        "Cavinium",
        "Callaum",
        "Gregorium",
        "Igthornium",
        "Scroogium",
        "Hueum",
        "Dewium",
        "Louium",
        "Webbium",
        "Beaklium",
        "Duckworthium",
        "Bubbium",
        "Tootsium",
        "Mcquackium",
        "Gearloosium",
        "Gizmodium",
        "Glomgoldium",
        "Beaglium",
        "Magica",
        "Drakium",
        "Gosalon",
        "Muddlefootium",
        "Morganium",
        "Hooterium",
        "Gryzlikoffium",
        "Negaduckium",
        "Bushrootium",
        "Megavoltium",
        "Jagaium",
        "Lionoium",
        "Tygram",
        "Panthron",
        "Cheetaram",
        "Snarfium",
        "Jemium",
        "Kimberium",
        "Ajaleithum",
        "Shanium",
        "Carmenium",
        "Pizzazzium",
        "Roxium",
        "Stormerium",
        "Jettium",
        "Riotium",
        "Rapturium",
        "Minxium",
        "Chippium",
        "Dalium",
        "Monterium",
        "Hackwrenchium",
        "Zipperium",
        "Fatcatium",
        "Nimnulum",
        "Tommium",
        "Chuckium",
        "Phillium",
        "Lillium",
        "Angelicum",
        "Susium",
        "Dillium",
        "Kimium",
        "Stuium",
        "Didium",
        "Drewium",
        "Bettium",
        "Renium",
        "Stimpium",
        "Muddium",
        "Powderedtoastium",
        "Optimusprimium",
        "Bumblebium",
        "Cliffjumperium",
        "Wheeljackium",
        "Prowlium",
        "Megatronium",
        "Soundwavium",
        "Shockwavium",
        "Skywarpium",
        "Starscreamium",
        "Gadgetium",
        "Pennium",
        "Brainium",
        "Clawium",
        "Quimbium",
        "Alvinium",
        "Simonium",
        "Theodorium",
        "Davium",
        "Brittanium",
        "Jeanettium",
        "Eleanorium",
        "Prefectium",
        "Dentium",
        "Beeblebroxium",
        "Trilliane",
        "Marvinium",
        "Slartium",
        "Deepthoughtium",
        "Vogone",
        "Jeltzium",
        "Eddium",
        "Fenchurchium",
        "Halfruntium",
        "Majikthise",
        "Vroomfondelium",
        "Colluphidium",
        "Alfium",
        "Gordonium",
        "Willium",
        "Katium",
        "Luckium",
        "Homerium",
        "Margium",
        "Bartium",
        "Lisium",
        "Maggium",
        "Nedium",
        "Toddium",
        "Roddium",
        "Burnsium",
        "Smitheron",
        "Karlium",
        "Lennium",
        "Moeium",
        "Barnium",
        "Krustium",
        "Skinnerium",
        "Mcclurium",
        "Mcbanium",
        "Itchium",
        "Scratchium",
        "Wiggium",
        "Springfieldium",
        "Murdockium",
        "Baracium",
        "Hanniblium",
        "Facium",
        "Martium",
        "Brownium",
        "Biffium",
        "Lorrainium",
        "Georgium",
        "Stricklandium",
        "Goldium",
        "Claytonium",
        "Hillvallium",
        "Deloreum",
        "Waynium",
        "Garthium",
        "Benjamine",
        "Cassandrium",
        "Vanderhoffium",
        "Stacium",
        "Buttercupium",
        "Westlium",
        "Inigon",
        "Fezzikium",
        "Vizzinium",
        "Humperdinkum",
        "Rugenium",
        "Maxium",
        "Valerium",
        "Sarahium",
        "Jarethium",
        "Tobium",
        "Hogglium",
        "Didymusium",
        "Simbium",
        "Mufasium",
        "Scarium",
        "Nalium",
        "Timonium",
        "Pumbaaium",
        "Rafikium",
        "Zazuium",
        "Sarabium",
        "Shenzium",
        "Banzium",
        "Edium",
        "Bellium",
        "Beastium",
        "Cogsworthium",
        "Pottsium",
        "Lumierium",
        "Gastonium",
        "Lefouium",
        "Mauricium",
        "Woodium",
        "Buzzium",
        "Slinkium",
        "Rexium",
        "Hammium",
        "Andium",
        "Siddium",
        "Smithium",
        "Philium",
        "Vivianium",
        "Carltonium",
        "Hilarium",
        "Ashlium",
        "Geoffrium",
        "Sinclarium",
        "Earlium",
        "Franium",
        "Robbium",
        "Charlenium",
        "Babium",
        "Ethylium",
        "Hessium",
        "Richfieldium",
        "Littlefootium",
        "Ceraium",
        "Duckium",
        "Petrium",
        "Spikium",
        "Longneckium",
        "Sharptoothium",
    };
}

Таким образом, мне не нужно беспокоиться о дополнительной сложности чтения файлов, и мы имеем дело только с несколькими сотнями элементов, о которых не стоит беспокоиться. В прошлом было большое предпочтение экстернализировать все (в частности, файлы свойств) для того «на всякий случай» момента, когда все должно быть изменено.  

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

Статический против Экземпляра

В последнее время я много спорил с людьми, и я просто не пришел к выводу и хотел бы услышать от вас, читателя. 

Возьмем, к примеру, код, который мы рассмотрели ранее из Drippel:

ChemicalNamer.generateAllSymbols(chemical);

Как правило, мне не нравятся статические вызовы методов. Они не объектно-ориентированные, поскольку являются чистыми функциями без состояния. В частности, поскольку этот метод вызывается неоднократно в цикле, я, вероятно, переместил бы его в метод экземпляра и вставил бы экземпляр ChemicalNamer сверху, что затем дает мне контроль над насмешкой.

Но что делать, когда у нас есть настоящая функция Util, то, что используется один раз и не имеет состояния? Если бы мы сделали это OO, код был бы ужасен, вот так:

new TextUtils().randomStringStartingWith("x--")

Если в TextUtils есть нулевое состояние, то оно должно быть статическим. Но, как я уже сказал, я думаю, что статические методы, как правило, не объектно-ориентированы. Я до сих пор не понял, что нужно делать, и продолжаю использовать статические методы — у тебя есть мысли?

Тестовые имена

Я рад видеть, что все решения пришли с тестами, но, похоже, проблема с именованием очевидна. Вот некоторые из имен тестов из различных решений; ты можешь сказать мне, что они делают?


@Test
public void accept() 


@Test
public void register()


@Test
public void test_4() 


@Test
public void test_5() 

Сделайте ваши тестовые имена описательными! Хорошее практическое правило заключается в том, что имена ваших тестов должны выступать в качестве удобочитаемой спецификации требований. Вы читаете названия тестов, вы знаете, что делает класс. В случае «accept ()» выше (взято отсюда ) я бы переименовал его в «validatesChemicalSymbolIsValidForElement ()». Теперь вы знаете, какая функциональность ожидается от реализации и что тест предназначен для ее выражения.

Как всегда, любые вопросы или дайте мне знать ваши мысли в комментариях. Несколько отличных решений на этой неделе, молодцы!