在没有接口的情况下从两个不同的 类 组继承的解决方案

Solutions for inheriting from two distinct groups of classes without Interfaces

我正在创建一个自动化测试套件,在网页之后建模 classes。我正在测试具有相同基本结构的 Web 门户,但门户之间存在差异。对于跨所有门户网站的所有网页通用的数据和方法,我希望 classes 继承自 class、BasePage。对于特定门户的所有网页还有其他门户上不存在的所有网页通用的方法,因此我想继承 class、<portal name>.BasePage

这里有点棘手。我还想从我所在的页面类型继承方法,例如BaseForgotPasswordPage。如果我的测试导航到特定门户的 忘记密码 页面,我将实例化 <portal name>.ForgotPasswordPage 并且我希望它能够访问 BasePage 中的方法, BasePortalPage,以及 BaseForgotPasswordPage。此叶子 class 需要从 BasePortalPageBaseForgotPasswordPage 继承,Java 有充分的理由不允许这样做。如果不创建数量可笑的 classes,它们也无法相互继承,因为 BaseForgotPasswordPage 适用于所有门户,而不仅仅是一个。问题就出在这里。

使用接口会导致跨不同 classes 的重复代码,我想保持我的代码干燥,这样就无济于事了。合并基础 classes 将赋予页面不应该有的行为。例如,如果我将 ForgotPasswordPage 合并到 BasePage,则每个网页都会有仅适用于 忘记密码 页面的方法。

可以降低设计复杂性的一个可能约束是不允许 class 中的一个数据,例如 BaseForgotPasswordPage。实际上,这个 class 成为一个模块,不需要被继承。尽管不是那么干净的方法,但它是我能想到的唯一可行的解​​决方案。任何其他建议将不胜感激。

如果您使用的是Java8,您可以在接口中使用默认方法实现以及组合。像这样:

public interface BasePage {

    BasePage basePageImpl = new BasePageImpl();

    default void basePageMethodOne() {
        basePageImpl.basePageMethodOne();
    }

    default void basePageMethodTwo() {
        basePageImpl.basePageMethodTwo();
    }
}

public class BasePageImpl implements BasePage {

    public void basePageMethodTwo(){
        System.out.println("Hello from Base Page method two");
    }

    public void basePageMethodOne(){
        System.out.println("Hello from Base Page method one");
    }
}

public interface BasePortalPage {

    BasePortalPage basePageImpl = new BasePortalPageImpl();

    default void basePortalPageMethodOne(){
        basePageImpl.basePortalPageMethodOne();
    }

    default void basePortalPageMethodTwo(){
        basePageImpl.basePortalPageMethodTwo();
    }
}

public class BasePortalPageImpl implements BasePortalPage {

    public void basePortalPageMethodTwo(){
        System.out.println("Hello from Base Portal Page method two");
    }

    public void basePortalPageMethodOne(){
        System.out.println("Hello from Base Portal Page method one");
    }
}

现在我们可以构建由 BasePage 和 BasePortalPage 组成的 BaseForgotPasswordPage

public class BaseForgotPasswordPage implements BasePage, BasePortalPage {

    public static void main(String ... x){

        BaseForgotPasswordPage myPage = new BaseForgotPasswordPage();

        myPage.basePageMethodOne();
        myPage.basePortalPageMethodOne();
        myPage.basePageMethodTwo();
        myPage.basePortalPageMethodTwo();
    }
}

结果是:

Hello from Base Page method one
Hello from Base Portal Page method one
Hello from Base Page method two
Hello from Base Portal Page method two

========= 编辑 =========

One question, why do we need the BasePageImpl and BasePortalPageImpl classes? My guess would be this is a Composition design constraint?

不,这不是组合约束。
是因为接口的功能有限,在接口本身做一个实现会有点困难。
考虑以下简短示例:

public interface MyInterface {

    int someVar = 20;  // no error 
    int var2;  // compile time error

private int myPrivate = 30; // error - only public, static & final are permitted

    MyIterface(){  // Constructor - compile time error

    }

    MyIterface(int parameter){  // Another constructor - compile time error 
    }

    default int someMethod( int parameter){
        int someOtherVar = 30;
        someVar ++; // compile time error - someVar is a final field, cannot be modified
        return someVar+parameter;
    }
}

正如你从这个例子中看到的那样 - 你不能声明构造函数,你不能声明字段,不能使用私有字段 - 只允许最终 public 和静态字段,但它们不能已修改 - 它们只是常量。
在委托中更容易做到这一点——真正的 class。该接口只是一个代理。