Здравствуйте, Cybernelly, Вы писали:
C>>А что тут такого? Почти что обычный CRTP (Curiously Recurring Template Pattern) Хотя, это мой опыт С++-ных темплейтов сказывается.... C>Да, вроде видел я такие вещи в ATL... Но там все было несколько сложнее, плюс множественное наследование.
Такой паттерн часто используется в тех случаях, когда в базовом классе есть функции, которые должны возвращать объект потомков.
Типа:
public void Session<T>
{
Set<Object> someSet;
public T addObject(Object some)
{
someSet.add(some);
return this;
}
}
public void AnotherSession extends Session<AnotherSession>
{
public AnotherSession addInteger(Integer i)
{
//...
}
//...
}
//Использовать так:
AnotherSession sess=...;
return sess.addObject("Hello").addInteger(11).addString("sadf");
В абстрактных классах это как раз нормально (хотя я бы написал SessionState вместо AbstractSession.State). С появлением Generics одна из функций абстрактных супертипов как раз стала в том, чтобы выполнить подстановки в шаблонах для использования в потомках.
Если у вас несколько разных типов сессий, которые активно используются, вы за счет минимального усложнения в супертипе сильно упрощаете остальной код.
Здравствуйте, Cyberax, Вы писали:
C>Такой паттерн часто используется в тех случаях, когда в базовом классе есть функции, которые должны возвращать объект потомков.
[skipped]
Сюда можно и такой пример привести, по сути меняем непараметризованный java.lang.Cloneable на свой параметризованный и обратно совместимый с первым — ICloneable<T>:
public interface ICloneable<T extends ICloneable<T>> extends Cloneable {
T clone();
}
public class MyClass implements ICloneable<MyClass> {
private final String field;
public MyClass(String field) {
if (field == null)
throw new NullPointerException();
this.field = field;
}
@Override
public MyClass clone() {
return new MyClass(field);
}
}
Здравствуйте, rsn81, Вы писали:
R>Сюда можно и такой пример привести, по сути меняем непараметризованный java.lang.Cloneable на свой параметризованный и обратно совместимый с первым — R>...
:
[skipped]
Суть-то в том, что ICloneable<T> типобезопасен: с ним вы физически уже не сможете ошибиться в возвращаемом типе методе clone — понятно, что мелочь, и все же.
: R>[skipped] R>Суть-то в том, что ICloneable<T> типобезопасен: с ним вы физически уже не сможете ошибиться в возвращаемом типе методе clone — понятно, что мелочь, и все же.
И все-таки, пример неважный. В данном примере covariant return настолько же типобезопасен, что и ICloneable<T>. В то же время отнаследоваться от MyClass используя ICloneable будет сложно.
public class MyClass implements ICloneable<MyClass> {
// ...
@Override
public MyClass clone() {
return new MyClass(...);
}
}
public class YourClass extends MyClass implements ICloneable<YourClass> {
// ICloneable cannot be inherited with different arguments: <YourClass> and <MyClass>
// ...
@Override
public YourClass clone() {
return new YourClass(...);
}
}
Ну и еще непонятно зачем ICloneable наследуется от java.lang.Cloneable если объекты клонируются конструктором.
Вполне читабельный код.
Как мне кажется дженерики здесь уместны, ведь их специально для того и придумали чтобы снизить риск получить ClassCastException в рантайме
А в этом примере кастить без дженериков пришлось бы оченб много.