簡體   English   中英

在Java中將基類轉換為派生類

[英]Casting a base class onto a derived class in Java

目前在我的Java程序中,我有一個基類Parent類,它有幾個返回其自身實例的方法。 例如:

public BasePage fill(String input, By locator) {
    driver.findElement(locator).clear();
    driver.findElement(locator).sendKeys(input);

    return new BasePage(driver);
}

同樣,我有幾個類用自己的方法擴展這個基類。 我的問題是:在我的主程序中是否有一種方法可以調用這些Parent方法,但是將返回的值分配給子類而不使用強制轉換? 例如,如果我有一個需要在主程序中使用此方法的loginPage Child類,我該怎么做:

loginPage = (LoginPage) loginPage.fill("username", usernameLocator);

進入這個:

loginPage = loginPage.fill("username", usernameLocator);

我初始化類的地方:

public class LoginPage extends BasePage {
}

雖然在這個例子中沒有提到,是否可以允許它返回任何子類,這樣它不僅限於一個類。

是的,有一種方法。 在子類(例如LoginPage )中,覆蓋fill方法。 使用Java的協變返回類型 (滾動到底部),可以將LoginPage指定為返回類型。

public LoginPage fill(String input, By locator) {
    driver.findElement(locator).clear();
    driver.findElement(locator).sendKeys(input);

    return new LoginPage(driver);
}

這假設你可以創建一個帶有driverLoginPage ,假定它是一個Driver類,這意味着你需要一個帶有Driver的子類構造函數。

public LoginPage(Driver driver)
{
    super(driver);
    // Anything else LoginPage-specific goes here
}

有幾種方法可以在這里繼續,但是如果新實例與舊實例幾乎相同,可能會進行一些修改,我認為您應該考慮使您的層次結構能夠克隆。

public class BasePage implements Cloneable {

    public BasePage fill(String input, By locator) {
        driver.findElement(locator).clear();
        driver.findElement(locator).sendKeys(input);

        return (BasePage) clone();
    }

    @Override
    protected Object clone() {
      try {  
        return super.clone();
      } catch ( CloneNotSupportedException ex) {
        throw new RuntimeException("this can't ever happen!!!",ex);
      } 
    }
...
}

然后子類需要使用適當的強制轉換覆蓋父級的填充

public class LoginPage extends BasePage {

    @Override
    public LoginPage fill(String input, By locator) {
        return (LoginPage) super.fill(input,locator);
    }
}

請注意,clone將始終返回原始調用實例的實例...在本例中為LoginPage。

這種方法可能不起作用或需要細化,具體取決於層次結構中的其他成員字段以及如何在克隆之間共享這些字段。

只要你保持所有子類的構造函數的簽名,在這種情況下(驅動程序),一個不同的方法是保持方法的邏輯填充父級並通過傳遞類選擇適當的子類賓語...

public class BasePage {

  public <T extends BasePage> T fill(String input, By locator, Class<T> clazz) {
    driver.findElement(locator).clear();
    driver.findElement(locator).sendKeys(input);
    // not sure if the cast is even needed.
    try {
      return (T) clazz.getConstructor(Driver.class).newInstance(driver);
    } catch (Exception ex) {
      throw new RuntimeException("whoops! something went wrong",ex);
    } 
  }
}

然后獲取LoginPage ...

 LoginPage lp = page.fill(input,loc,LoginPage.class);

您可以重載子類中的填充以避免傳遞類,但是我們將像上面的克隆解決方案一樣工作。

不,不是這樣的。 如果BasePage是您調用給定fill()方法的引用的正式類型,則返回值的正式類型是BasePage 如果沒有強制轉換,您不能將該值視為BasePage的子類型。

在您的特定示例中,即使轉換也應該因ClassCastException而失敗,因為子類的方法(子類未顯示為覆蓋)返回其類為BasePage的對象,並且此類對象不是LoginPage的實例。

但是,子類可以使用協變返回類型覆蓋該方法:

public class LoginPage extends BasePage {
    @Override
    public LoginPage fill(String input, Locator by) {
        return new LoginPage(/* ... */);
    }
}

在這種情況下,如果調用該方法上的一個參考LoginPage (或它的子類中的一個),則返回值是一個實例LoginPage並且可以作這樣的處理:

LoginPage page1 = new LoginPage();
LoginPage page2 = page1.fill("username", usernameLocator);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM