2016-05-13 1 views
0

Je crée une suite de tests automatisée en modélisant des classes après des pages web. Je teste les portails Web avec la même structure de base, mais des différences existent entre les portails. Pour les données et les méthodes communes à toutes mes pages Web sur tous les portails, je souhaite que les classes héritent d'une classe, BasePage. Il existe également des méthodes communes à toutes les pages Web pour un portail particulier qui n'existent pas sur d'autres portails, donc j'aimerais hériter d'une classe, <portal name>.BasePage.Solutions pour hériter de deux groupes distincts de classes sans Interfaces

Ici, c'est difficile. Je veux également hériter des méthodes du type de page sur lequel je suis, par exemple. BaseForgotPasswordPage. Si mon test accède à la page Mot de passe oublié d'un portail particulier, j'instancie <portal name>.ForgotPasswordPage et je souhaite qu'il accède aux méthodes en BasePage, BasePortalPage et BaseForgotPasswordPage. Cette classe feuille doit hériter à la fois de BasePortalPage et de BaseForgotPasswordPage, ce que Java n'autorisera pas pour de bonnes raisons. Ils ne peuvent pas non plus hériter l'un de l'autre sans créer une quantité ridicule de classes car BaseForgotPasswordPage s'applique à tous les portails, pas seulement un. Là réside le problème. L'utilisation d'Interfaces conduira à dupliquer le code entre les différentes classes et je veux garder mon code DRY, ce qui ne servira à rien. La consolidation des classes de base donnera un comportement de page qu'il ne devrait pas avoir. Par exemple, si je fusionne ForgotPasswordPage en BasePage, chaque page Web aura des méthodes applicables uniquement à la page Mot de passe oublié.

Une contrainte possible qui pourrait faciliter la complexité de la conception est l'interdiction de données dans l'une des classes comme BaseForgotPasswordPage. En effet, cette classe devient un module et n'aura pas besoin d'être héritée. Bien que pas aussi propre d'une approche, c'est la seule solution viable que je pourrais penser. Toute autre suggestion serait la bienvenue.

+0

C'est un peu difficile de répondre car je ne sais pas à quoi ressemble chaque classe. Que diriez-vous de faire l'héritage à plusieurs niveaux - 1) BasePage 2) BasePortalPage étend BasePage 3) BaseForgotPasswordPage étend BasePortalPage? De même, vous n'avez pas besoin d'hériter pour réutiliser le code. Alternativement, certaines personnes pourraient aussi argumenter "Composition sur l'héritage". Vous pouvez simplement avoir l'objet et utiliser sa méthode et autres. Par exemple, BaseForgotPasswordPage a des objets d'instance pour BasePage et BasePortalPage. – Tin

Répondre

2

Si vous utilisez Java 8, vous pouvez utiliser une implémentation de méthode par défaut dans les interfaces avec une composition. Quelque chose comme ceci:

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"); 
    } 
} 

Et maintenant, nous pouvons construire notre BaseForgotPasswordPage qui est composé de BasePage et BasePortalPage

public class BaseForgotPasswordPage implements BasePage, BasePortalPage { 

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

     BaseForgotPasswordPage myPage = new BaseForgotPasswordPage(); 

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

et un résultat est:

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 

========= ========= EDIT

Une question, pourquoi avons-nous besoin des classes BasePageImpl et BasePortalPageImpl ? Je suppose qu'il s'agit d'une contrainte de conception de composition?

Non, ce n'est pas une contrainte de composition.
C'est parce que les fonctionnalités de l'interface sont limitées, il serait un peu difficile de faire une implémentation dans l'interface elle-même.
Tenir compte du court ci-dessous par exemple:

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; 
    } 
} 

Comme vous le voyez de cet exemple - vous ne pouvez pas déclarer les constructeurs, vous ne pouvez pas déclarer des champs, ne peut pas utiliser des champs privés - seuls les champs statiques & publics finaux sont autorisés, mais ils ne peuvent pas être modifiés - ils sont simplement des constantes.
Il est plus facile de le faire dans un délégué - une classe réelle. L'interface est seulement un proxy.

+0

Brillant! Juste ce que je cherchais, merci. Une question, pourquoi avons-nous besoin des classes 'BasePageImpl' et' BasePortalPageImpl'? Je suppose qu'il s'agit d'une contrainte de conception de composition? – Steve

+1

J'ai ajouté une explication à la réponse – krokodilko

+0

Oui, maintenant je comprends. Je vous remercie! – Steve