Я пишу свободный API для настройки и создания последовательности объектов "сообщения". У меня есть иерархия типов сообщений.
Чтобы иметь возможность получить доступ к методу подклассов при использовании свободного API, я использовал generics для параметризации подклассов и создания всех свободно используемых методов (которые начинаются с "с" ) возвращают общий тип. Обратите внимание, что я пропустил большую часть тела свободного метода; в них много конфигурации.
public abstract class Message<T extends Message<T>> {
protected Message() {
}
public T withID(String id) {
return (T) this;
}
}
Конкретные подклассы также переопределяют общий тип.
public class CommandMessage<T extends CommandMessage<T>> extends Message<CommandMessage<T>> {
protected CommandMessage() {
super();
}
public static CommandMessage newMessage() {
return new CommandMessage();
}
public T withCommand(String command) {
return (T) this;
}
}
public class CommandWithParamsMessage extends
CommandMessage<CommandWithParamsMessage> {
public static CommandWithParamsMessage newMessage() {
return new CommandWithParamsMessage();
}
public CommandWithParamsMessage withParameter(String paramName,
String paramValue) {
contents.put(paramName, paramValue);
return this;
}
}
Этот код работает, т.е. я могу создать экземпляр любого из классов и использовать все текущие методы:
CommandWithParamsMessage msg = CommandWithParamsMessage.newMessage()
.withID("do")
.withCommand("doAction")
.withParameter("arg", "value");
Вызов быстрых методов в любом порядке - главная цель здесь.
Однако компилятор предупреждает, что все return (T) this
являются небезопасными.
Тип безопасности: снятие флажка из сообщения в T
Я не знаю, как я мог бы реорганизовать иерархию, чтобы сделать этот код действительно безопасным. Несмотря на то, что это работает, использование дженериков в этом способе кажется действительно запутанным. В частности, я не могу предвидеть ситуации, когда исключения выполнения выполняются, если я просто игнорирую предупреждения. Появятся новые типы сообщений, поэтому мне нужно сохранить код расширяемым. Если решение состоит в том, чтобы вообще избежать наследования, я также хотел бы получить предложение об альтернативах.
другие вопросы здесь, на SO, которые касаются аналогичной проблемы. Они указывают на решение, где все промежуточные классы абстрактны и объявляют метод, подобный protected abstract self()
. Тем не менее, в конце концов, это не безопасно.