Передача в родительский элемент информации о том кто вызвал метод родительского класса

Рейтинг: 1Ответов: 2Опубликовано: 25.04.2023

Вопрос заключается в том, что у меня есть классы, которые описывают веб-элементы (Button, Input и т.д).

Я решил создать базовый класс, от которого они все наследуются (BaseElement) и вынести в него все методы, которые можно сделать над всеми элементами (click, move и прочее), но из-за того, что я везде использую return this, чтобы просто через точку вызывать методы, когда я вызываю сначала метод родителя, мне перестают быть доступны методы потомка.

Есть возможность из родителя возвращать ссылку на объект, который и вызвал метод родителя?

Пример метода родителя:

public BaseElement clickElement() {
    Allure.step("Клик на " + typeElement + " " + getName() + "'");
    WaitT.elementToBeClickable(this.getWrappedElement());
    this.getWrappedElement().click();
    return this;
}

Пример метода потомка:

public CheckBox enableCheckBox() {
    if (!isChecked()){
        Allure.step("Клик по чек-боксу '" + getName() + "'");
        WaitT.elementToBeClickable(this.getWrappedElement());
        this.getWrappedElement().click();
    }
    return this;
}

Пример использования, тут ошибка, потому что метод родителя вернул BaseElement, а не TextBox:

var loginPage = new LoginPage();
    loginPage.loginUser.clickElement().enterTextFromTextBox(LOGIN);

Ответы

▲ 0Принят

Если метод класса возвращает this, то это не значит, что он фактически возвращает объект ровно от данного класса.

Класс ведь может быть и абстрактным, а от абстрактного класса объекты не могут быть созданы вообще. Что в таком случае означает возврат this? Он означает возврат объекта от того класса, для которого этот метод родителя был вызван.

Да, возвращаемый тип у метода - родительский. Но в месте вызова метода мы ведь точно знаем класс, объект от которого вызывает этот метод. Соответственно, можем не боясь ошибок использовать приведение типов, что и будет продемонстрировано ниже.

Родительский класс:

public abstract class SuperClass {
    public SuperClass superClassMethod() {
        System.out.println("SuperClass hello!");
        return this;
    }
}

Подкласс:

public class FirstSubClass extends SuperClass {
    public FirstSubClass firstSubClassMethod() {
        System.out.println("FirstSubClass hello!");
        return this;
    }
}

Как делается приведение типов в этом случае:

public class Main {
    public static void main(String[] args) {
        FirstSubClass first = new FirstSubClass();
        ((FirstSubClass) first.superClassMethod()).firstSubClassMethod();
        // привели к FirstSubClass, ведь точно знаем, что родительский метод вернёт объект именно от него
    }
}

Результат:

SuperClass hello!
FirstSubClass hello!
▲ 1

В классах наследниках можно переопределить необходимые методы, указав при этом класс наследника как возвращаемый тип

class BaseElement {
    public BaseElement clickElement() {
        return this;
    }
}

class CheckBox extends BaseElement {

    @Override
    public CheckBox clickElement() {
        super.clickElement();
        return this;
        // либо так
        // return (CheckBox) super.clickElement();
    }

    public CheckBox enableCheckBox() {
        return this;
    }
   
}


new CheckBox().clickElement().enableCheckBox();
new BaseElement().clickElement()
// .enableCheckBox() - compile error