Задать вопрос
@pqgg7nwkd4

Как сделать цепочки в наследующих классах java?

Добрый день.

Исходные данные: есть желание использовать Method chainig, т. к. это часто удобно.

Возьмем в пример: "животные".
Пусть есть родительский класс для всех животных, который поддерживает цепочки:
class Animal {
    public Animal setWeight(int newWeight) {
        return this;
    }
    public Animal setName(String newName){
        return this;
    }
}

// Как работает?
Animal animal = new Animal().setName("Murzik").setWeight(20);

// Удобно!


Всё красиво и просто. Теперь усложним задачу. Добавим кота:
class Cat extends Animal {
    public Cat setMeowVolume(int volume) {
        return this;
    }
}


Возникает проблема: методы setWeight и setName возвращают Animal и следующие конструкции работать не будут:
Cat cat1 = new Cat().setName("Murzik").setWeight(20).setMeowVolume(100); // Ошибка: setMeowVolume - не найден
Cat cat2 = new Cat().setMeowVolume(100).setName("Murzik").setWeight(20); // Ошибка: setWeight не возвращает Cat


Можно, конечно, применить кастинг. Но получается ужасно:
Cat cat1 = ((Cat)new Cat().setName("Murzik").setWeight(20)).setMeowVolume(100);
Cat cat2 = (Cat)new Cat().setMeowVolume(100).setName("Murzik").setWeight(20);


Можно наследовать все методы в Cat.
class Animal  {
    public Animal setWeight(int newWeight) {
        return this; 
    }
    public Animal setName(String newName){
        return this; 
    }
}

class Cat extends Animal {
    @Override
    public Cat setWeight (int newWeight) {
        super.setWeight(newWeight);
        return this;
    }

    @Override
    public Cat setName (String newName) {
        super.setName(newName);
        return this;
    }

    public Cat setMeowVolume(int volume) {
        return this;
    }
}

// Работает замечательно
Cat cat1 = new Cat().setName("Murzik").setWeight(20).setMeowVolume(100);
Cat cat2 = new Cat().setMeowVolume(100).setName("Murzik").setWeight(20);

// Проблемы:
// 1. Увеличение кода
// 2. Наследование методов там, где не оно не требуется.


Еще один способ. Он менее плох, но всё-же не так удобен как хотелось бы:
class Animal <Return extends Animal<Return>> {
    public Return setWeight(int newWeight) {
        return (Return)this; // Unchecked cast warning
    }
    public Return setName(String newName){
        return (Return)this; // Unchecked cast warning
    }
}
class Cat<Return extends Cat<Return>> extends Animal<Return> {
    public Return setMeowVolume(int volume) {
        return (Return)this; // Unchecked cast warning
    }
}

// Работает:
Cat cat1 = new Cat<>().setName("Murzik").setWeight(20).setMeowVolume(100);
Cat cat2 = new Cat<>().setMeowVolume(100).setName("Murzik").setWeight(20);

// Проблемы:
// 1. Куча предупреждений Unchecked cast.
// 2. Класс Cat становится generic-ом со всеми вытекающими последствиями и предупреждениями. (Например, конструктор необходимо указывать со скобками: new Cat<>()).
// 3. Грамозкое и малопонятное объявление классов.


Вот было бы здорово, если бы все void методы про вызове возвращали бы сам объект, или был бы возможен такой синтаксис:
class Animal  {
    public this setWeight(int newWeight) {

    }
    public this setName(String newName){

    }
}

class Cat extends Animal {
    this setMeowVolume(int volume) {
        
    }
}


Может быть я что-то упускаю?

Как бы вы организовали наследуемые классы с поддержкой chain вызовов?
  • Вопрос задан
  • 329 просмотров
Подписаться 2 Оценить 2 комментария
Пригласить эксперта
Ответы на вопрос 3
@Free_ze
Пишу комментарии в комментарии, а не в ответы
Переопределяйте базовые методы.
Ответ написан
Комментировать
Чтобы избежать unchecked warning можно ещё вот так:
class Animal <Return extends Animal<Return>> {
    public Return setWeight(int newWeight) {
        return self();
    }
    public Return setName(String newName){
        return self();
    }
    @SuppressWarnings("unchecked")
    protected Return self() {
        return (Return) this;
    }
}
class Cat<Return extends Cat<Return>> extends Animal<Return> {
    public Return setMeowVolume(int volume) {
        return self();
    }
}
Ответ написан
Комментировать
jamakasi666
@jamakasi666 Куратор тега Java
Просто IT'шник.
Не сталкивался с подобными задачами как и никогда не использовал цепочки. Я конечно далекий от таких тонкостей и проблем как в вашем случае но может стоит попытаться написать серебряную пулю через аннотация\рефлексии?
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы