使用抽象类型变量中的具体 class
Using concrete class from a abstract type variable
如果这个问题已经被问到,我很抱歉,我还没有找到类似我的问题的东西...
我 working/playing/learning 建立某种测试环境...在其中,我正在构建一个应用层(一个 classes 的包,它是应用程序的不同 pages/windows/forms)。简化设置如下:
public abstract class WebPage {
protected WebDriver driver;
protected WebElement getElement(By by){
WebElement element = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(by));
return element;
}
public void menuLogout(){
System.out.println("Logged out");
}
}
public class HomePage extends WebPage {
public ProfilePage ClickLinktoProfilePage(){
return new ProfilePage();
}
public DashBoardPage clickViewDashboard(){
return new DashBoardPage();
}
public String getTitle(){
return getElement(By.id("title")).getText();
}
}
public class ProfilePage extends WebPage {
public String getUsername(){
return getElement(By.id("name")).getText();
}
public String getEmail(){
return getElement(By.id("email")).getText();
}
public HomePage clickReturnToHomePage(){
return new HomePage();
}
}
public class DashBoardPage extends WebPage {
public String getcurrentPeriod(){
return getElement(By.id("name")).getText();
}
}
这背后的想法是我希望我的测试只包含一个当前网页。我不希望每次更改页面时都创建一个新变量。
我也不想被迫提前知道我要进入哪个页面。我要应用层给我应用的流程。与单击 link 时将您带到下一页的方式相同,我希望当我单击将我带到另一页的 link 时,该方法会告诉我我在哪个页面前往。
(WebPage 抽象 class 还公开了所有具体 WebPage 之间的许多共享方法)
所以我的预期用途是:
WebPage currentPage = new HomePage();
currentPage = currentPage.ClickLinktoProfilePage(); //currentPage = new ProfilePage();
System.out.println(currentPage.getUsername());
currentPage.menuLogout();
遗憾的是,这不起作用,因为 currentPage 变量的类型是 WebPage,它看不到任何具体的 classes 方法。我觉得它既合乎逻辑又奇怪,因为我可以问 "currentPage.getClass().getName();" 并且它会 return "packageName.ConcreteClassName".
要使类型转换正常工作,我需要重新定义变量的类型...(不确定是否可行,甚至是否可行)。
所以我知道我可以在变量中找到 class 的名称,但我不确定从那里去哪里。
有人有解决办法吗?
澄清一下 Radiodef 和我在此处的评论中所说的内容:
你想要的是定义WebPage
(你的抽象API),这样你的具体子class就不需要 有 public 不属于 API 的方法。
例如对比标准库中的java.util.List
接口。这个接口有多种实现(ArrayList
和 LinkedList
是最著名的,但还有很多其他的),但是大多数使用 List
的代码并不需要关心它是否实际使用 ArrayList
或 LinkedList
或其他东西,因为您需要的所有操作都通过 List
接口公开。
您可以用 WebPage
class 做同样的事情。例如,您可以为可以对网页执行的不同操作定义一系列 "hooks":
public abstract class WebPage {
// methods that each subclass needs to implement
protected abstract String renderBodyHtml();
public abstract String getNameToLinkTo();
// other methods that are common to every page
public final void serve(
HttpServletRequest request, HttpServletResponse response) {
// write the response, using the specific page's body HTML
response.getWriter().println(renderToBodyHtml());
}
}
然后您的页面将像这样实施 合同:
// Note: the class doesn't need to be public, since anybody that uses
// it can just declare their variable as type WebPage
class Page1 extends WebPage {
@Override protected String renderBodyHtml() {
return "<body>Hello world!</body>";
}
@Override public String getNameToLinkTo() {
return "Page1";
}
}
然后想要使用 WebPage
的代码不需要知道它是 Page1
(或任何其他页面):
public static void printPageName(WebPage webPage) {
System.out.println(webPage.getNameToLinkTo());
}
或者,如 resueman 所说,您可以直接使用 Page1
、Page2
等类型,使用 WebPage
仅用于实现继承,而不是 API.这也很好——正确的解决方案取决于您希望代码的灵活性(和复杂性)。
如果这个问题已经被问到,我很抱歉,我还没有找到类似我的问题的东西...
我 working/playing/learning 建立某种测试环境...在其中,我正在构建一个应用层(一个 classes 的包,它是应用程序的不同 pages/windows/forms)。简化设置如下:
public abstract class WebPage {
protected WebDriver driver;
protected WebElement getElement(By by){
WebElement element = (new WebDriverWait(driver, 10))
.until(ExpectedConditions.presenceOfElementLocated(by));
return element;
}
public void menuLogout(){
System.out.println("Logged out");
}
}
public class HomePage extends WebPage {
public ProfilePage ClickLinktoProfilePage(){
return new ProfilePage();
}
public DashBoardPage clickViewDashboard(){
return new DashBoardPage();
}
public String getTitle(){
return getElement(By.id("title")).getText();
}
}
public class ProfilePage extends WebPage {
public String getUsername(){
return getElement(By.id("name")).getText();
}
public String getEmail(){
return getElement(By.id("email")).getText();
}
public HomePage clickReturnToHomePage(){
return new HomePage();
}
}
public class DashBoardPage extends WebPage {
public String getcurrentPeriod(){
return getElement(By.id("name")).getText();
}
}
这背后的想法是我希望我的测试只包含一个当前网页。我不希望每次更改页面时都创建一个新变量。
我也不想被迫提前知道我要进入哪个页面。我要应用层给我应用的流程。与单击 link 时将您带到下一页的方式相同,我希望当我单击将我带到另一页的 link 时,该方法会告诉我我在哪个页面前往。
(WebPage 抽象 class 还公开了所有具体 WebPage 之间的许多共享方法)
所以我的预期用途是:
WebPage currentPage = new HomePage();
currentPage = currentPage.ClickLinktoProfilePage(); //currentPage = new ProfilePage();
System.out.println(currentPage.getUsername());
currentPage.menuLogout();
遗憾的是,这不起作用,因为 currentPage 变量的类型是 WebPage,它看不到任何具体的 classes 方法。我觉得它既合乎逻辑又奇怪,因为我可以问 "currentPage.getClass().getName();" 并且它会 return "packageName.ConcreteClassName".
要使类型转换正常工作,我需要重新定义变量的类型...(不确定是否可行,甚至是否可行)。
所以我知道我可以在变量中找到 class 的名称,但我不确定从那里去哪里。
有人有解决办法吗?
澄清一下 Radiodef 和我在此处的评论中所说的内容:
你想要的是定义WebPage
(你的抽象API),这样你的具体子class就不需要 有 public 不属于 API 的方法。
例如对比标准库中的java.util.List
接口。这个接口有多种实现(ArrayList
和 LinkedList
是最著名的,但还有很多其他的),但是大多数使用 List
的代码并不需要关心它是否实际使用 ArrayList
或 LinkedList
或其他东西,因为您需要的所有操作都通过 List
接口公开。
您可以用 WebPage
class 做同样的事情。例如,您可以为可以对网页执行的不同操作定义一系列 "hooks":
public abstract class WebPage {
// methods that each subclass needs to implement
protected abstract String renderBodyHtml();
public abstract String getNameToLinkTo();
// other methods that are common to every page
public final void serve(
HttpServletRequest request, HttpServletResponse response) {
// write the response, using the specific page's body HTML
response.getWriter().println(renderToBodyHtml());
}
}
然后您的页面将像这样实施 合同:
// Note: the class doesn't need to be public, since anybody that uses
// it can just declare their variable as type WebPage
class Page1 extends WebPage {
@Override protected String renderBodyHtml() {
return "<body>Hello world!</body>";
}
@Override public String getNameToLinkTo() {
return "Page1";
}
}
然后想要使用 WebPage
的代码不需要知道它是 Page1
(或任何其他页面):
public static void printPageName(WebPage webPage) {
System.out.println(webPage.getNameToLinkTo());
}
或者,如 resueman 所说,您可以直接使用 Page1
、Page2
等类型,使用 WebPage
仅用于实现继承,而不是 API.这也很好——正确的解决方案取决于您希望代码的灵活性(和复杂性)。