Java Fluent API - лучший метод?

Скажем, у меня есть объект, который я создал, чтобы еще больше упростить чтение XML-документа с помощью анализатора DOM. Чтобы "войти" в узел или элемент, я бы хотел использовать одну строку для перехода от начала документа к моим целевым данным, скрытым где-то в документе, обходя при этом дополнительный "поток" DOM парсер (такой как doc.getElementsByTagName("data").item(0) когда внутри элемента "data" есть только один элемент).

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

public class SimplifiedReader {
    Document doc;
    Element ele;
    public SimplifiedReader(Document doc) {
        this.doc = doc;
        ele = doc.getDocumentElement();
    }

    public SimplifiedReader fromRoot() {
        ele = doc.getDocumentElement();
        return this;
    }

    public SimplifiedReader withEle(String elementName) {
        ele = ele.getElementsByTagName(elementName).item(0);
        return this;
    }

    public String getTheData(String elementName) {
        return ele.getTextContent();
    }
}

Пример XML-файла:

<?xml version="1.0" encoding="UTF-8"?>
<fileData>
    <subData>
        <targetData>Hello World!</targetData>
        <otherData>FooBar!</otherData>
    </subData>
</fileData>

В результате я могу перемещаться по XML-файлу и получать Strings "Привет, мир!" и "FooBar!" используя этот код:

SimplifiedReader sr = new SimplifiedReader(doc);
String hwData = sr.withEle("fileData").withEle("subData").getTheData("targetData");
String fbData = sr.getTheData("otherData");

Или, если бы мне пришлось перейти в другой поток, чтобы получить данные "FooBar!", Я бы просто сделал:

String fbData = sr.fromRoot().withEle("fileData2").withEle("subData2").getTheData("otherData");

Есть ли лучший / более правильный способ сделать это? Редактировать: Примечание: этот вопрос больше о методе возврата объекта из метода внутри него (return this;), чтобы уменьшить количество кода, написанного для доступа к конкретным данным, хранящимся в древовидном формате, а не столько о том, как читать XML-файл. (Первоначально я думал, что это паттерн Синглтона, пока Уильям не поправил меня... спасибо, Уильям).

Заранее благодарю за любую помощь.

2 ответа

Решение
  1. Я не вижу здесь никаких следов паттерна синглтона. Он в основном напоминает шаблон Builder, но не так ли. Он просто реализует свободный API.

  2. Ваш подход кажется очень хорошим и практичным.

  3. Я бы посоветовал не использовать fromRoot() но вместо этого каждый раз создаю новый экземпляр. Экземпляр довольно легкий, так как все тяжелые вещи находятся в Document экземпляр это оборачивает.

  4. Вы могли бы даже стать неизменным, возвращая новый экземпляр из withEle(), Это дает вам много интересных свойств, таких как свобода обмениваться объектом вокруг, каждый путь кода может свободно использовать его в качестве отправной точки для извлечения чего-то определенного относительно него, совместного использования его между потоками и т. Д. Document является изменяемым, но обычно это не создает реальных проблем, когда весь код предназначен для чтения.

Есть ли лучший / более правильный способ сделать это?

Да, есть много лучших способов извлечь значения из XML.

Можно было бы использовать XPath, например, с XMLBeam.

import java.io.IOException;
import org.xmlbeam.XBProjector;
import org.xmlbeam.annotation.XBDocURL;
import org.xmlbeam.annotation.XBRead;

public class App {

    public static void main(String[] args) throws IOException {
        FileDate fileDate = new XBProjector().io().fromURLAnnotation(FileDate.class);
        System.out.println(fileDate.getTargetDate());
        // Hello World!
        System.out.println(fileDate.getOtherDate());
        // FooBar!
    }

    @XBDocURL("resource://filedate.xml")
    public interface FileDate {

        @XBRead("/fileData/subData/targetData")
        String getTargetDate();

        @XBRead("/fileData/subData/otherData")
        String getOtherDate();
    }
}
Другие вопросы по тегам