Наследование Java с использованием шаблона builder

у меня 3 класса:

  1. ShellError
  2. WebError

здесь

ShellError extends Error 

и

WebError extends Error

на ShellError есть поля, некоторые из которых являются обязательными, а остальные являются обязательными. Я строю объект следующим образом:

shellError = new ShellError.Builder().setFile(filePattern)
.setHost(host).setPath(path).setSource(file.isSource())
.setJobName(p.getJobName()).build();

С ShellError выходит Error, Я:

shellError.setDescription(msg.toString());
shellError.setExceptionClass("MyEvilException");
shellError.setExceptionMessage("Some clever error message");
shellError.setStacktrace(stack);

так ... зачем возиться со Строителем? Мне нравится тот факт, что моя build () среди прочего удобно проверяет, что все поля установлены соответствующим образом и т. д.

Я бы с удовольствием, если бы мог .. build ()ShellError и добавьте к нему поля из Error класса.

что я сделал работает.

  • вопрос:

есть ли лучший способ, или есть ли смысл, что я сделал?

-- EDIT

я обновил Builder () до примите некоторые из параметров, которые ранее были в классе ошибок. Теперь у меня есть

shellError = new ShellError.Builder(exception, "Some description").setFile(filePattern).setHost(host)
.setPath(path).setSource(file.isSource()).
setJobName(p.getJobName()).build();

что скажешь? лучше? Хуже?

3 ответов


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

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

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


на шаблона, популяризированный Джош блох, имеет преимущества, но он не работает так элегантно на родительских / подклассах, как описано в это обсуждение нашими коллегами в мире c#. Лучшее решение, которое я видел до сих пор, это этот (или легкий вариант of it).


Как уже было сказано, шаблон builder не является тем, что может органично вписаться в существующую политику инициализации объектов Java. Существует несколько подходов к достижению требуемого результата. Хотя, конечно, всегда лучше избегать любых двусмысленных практик, это не всегда возможно. Мой Хак основан на API отражения Java с дженериками:

abstract public class AbstractClass {

    public static class Builder {

        public <T extends AbstractClass> T build(Class<T> implementingClass) {
            try {
                Constructor<T> constructor = implementingClass
                        .getConstructor(new Class[]{Builder.class});
                return constructor.newInstance(this);
            } catch (NoSuchMethodException e) {
                // TODO handle the exception
            } catch (InvocationTargetException | InstantiationException |
                     IllegalAccessException  e) {
                // TODO handle the exception
            }
        }
    }

    protected AbstractClass(Builder builder) {

    }
}

public class ImplementingClass extends AbstractClass {

    public ImplementingClass (Builder builder) {
        super(builder);
    }
}

инициализации:

ImplementingClass instance = new AbstractClass.Builder()
                    .build(ImplementingClass.class);