2016-06-14 2 views
-1

En résumé, j'aimerais pouvoir regrouper des instances de classe par une superclasse qui n'implémente pas une certaine interface. Mais à partir de l'ensemble des instances que je voudrais appeler des méthodes de l'interface sur les instances qui implémentent cette interface.Bascule l'objet vers l'interface

Un exemple de code qui pourrait l'expliquer.

class Building{ 
    String c = "white"; 
    Building(){ 
    } 

    void printColor(){ 
    println("The building is " + c); 
    } 

    void paint(String c){ 
    this.c = c; 
    } 

    void printBuildQuality(){ 
    println("The build quality is average"); 
    } 
} 


class SturdyFactoryBuilding extends Building implements Factory{ 

SturdyFactoryBuilding(){ 
    super(); 
} 

void printBuildQuality(){ 
    println("The build quality is sturdy"); 
} 

void printFactoryOutput(){ 
    println("This factory makes stuff"); 
} 
} 

class ShakyFactoryBuilding extends Building implements Factory{ 

    ShakyFactoryBuilding(){ 
    super(); 
    } 

    void printBuildQuality(){ 
    println("The build quality is shaky"); 
    } 

    void printFactoryOutput(){ 
    println("This factory makes slightly different stuff"); 
    } 
} 


public interface Factory{ 

    public void printFactoryOutput(); 

} 

Building building = new SturdyFactoryBuilding();  
building.printBuildQuality(); 
building.printColor(); 
building.paint("bright red"); 
building.printColor(); 
building.printFactoryOutput(); 

Est-il possible que je peux y arriver, peut-être en ayant un drapeau « isFactory » dans la superclasse.

Merci.

+3

Vous pouvez le réaliser avec une simple vérification 'if (build instanceof Factory)'. Cependant, ce que vous essayez de faire ne serait pas considéré comme un bon design. – Kayaman

+0

Je vois @Kayaman, comme ceci: 'if (build instanceof Factory) { SturdyFactoryBuilding sfb = (SturdyFactoryBuilding) bâtiment; sfb.printFactoryOutput(); } 'Je peux voir comment ce ne serait pas une bonne conception, car j'ai encore besoin de tomber dans une sous-classe spécifique. Y a-t-il une meilleure façon de s'y prendre? – Bluefarmer

+0

Vous pouvez ajouter 'printFactoryOutput' à' Building' en lui donnant une implémentation par défaut NOOP. Les usines remplacent cette valeur par défaut. Genre d'une approche d'adaptateur. – Fildor

Répondre

0

Je pense que vous aurez à faire un compromis: Soit vous acceptez certains anti-modèle ou vous ouvrez vous Building « interface » d'agir comme un adaptateur:

class Building implements Factory{ 

    // the other building stuff 

    @Override 
    public void printFactoryOutput(){ /* NO OP */ } 
} 

Ensuite, vous pouvez appeler printFactoryOutput sur tous Building s n'ayant aucun effet jusqu'à ce point.

Depuis vos Factory -implémentations étendre Building héritent automatiquement l'implémentation NOOP. Mais puisque vous l'annulez:

class ShakyFactoryBuilding extends Building implements Factory{ 

    ShakyFactoryBuilding(){ 
    super(); 
    } 

    @Override 
    public void printBuildQuality(){ 
    println("The build quality is shaky"); 
    } 

    @Override 
    public void printFactoryOutput(){ 
    println("This factory makes slightly different stuff"); 
    } 
} 

... vous avez le résultat désiré. L'inconvénient est évidemment que tous les bâtiments ont printFactoryOutput visibles. Mais c'est le compromis dont je parlais. Si ce n'est pas acceptable, vous devrez complètement reconsidérer votre conception.

Pour bien faire comprendre qu'un bâtiment qui est pas une usine ne doit pas être appelée que la méthode, vous pourrait jeter un UnsupportedOperationException dans le bâtiment, mais cela forcerait les blocs try/catch partout dans votre code. Vous pourriez aussi bien renvoyer un booléen: default = false et renvoyer vrai si en fait une usine ... Il y a beaucoup de possibilités. Vous pouvez également changer votre conception pour utiliser composition over inheritance.

+0

Merci pour l'explication. Je vais retravailler la superclasse pour implémenter les méthodes d'interface. Il maintient les inconvénients (au moins sans une refonte) à un minimum pour moi. Lorsque l'interface Factory est implémentée dans la superclasse, il n'est pas nécessaire que les sous-classes qui implémentent également Factory aient leurs propres substitutions de méthode. Y a-t-il un moyen de forcer à être ainsi ou pourrait-on exclure des usines? Je vais accepter votre réponse, car elle répond à ma question principale. – Bluefarmer

+0

Puisque Building implémente Factory, vous pouvez supprimer cela des classes XXXFactory, oui. – Fildor

0

Je pense que vous recevez le message que c'est une mauvaise idée. Il viole les principes de conception orientés objet généralement acceptés. Cela dit, il y a plusieurs façons de s'y prendre, certaines moins odieuses que d'autres.

Juste jetteras

La chose la plus simple à faire est quelque chose comme ceci:

if (building instanceof Factory) 
    ((Factory)building).printFactoryOutput(); 

Vous vérifier pour voir si elle est un Factory, puis en appelant la méthode Factory après la coulée spécifique de. C'est une façon simple (et donc facile à comprendre) de mettre en œuvre un mauvais design.

Faire Building au courant de Factory

Cela a des problèmes dans qu'il n'y a actuellement aucun lien nécessaire entre Building et Factory, mais une telle relation peut vous aider.

class Building { 
    // ... 
    Factory adaptToFactory() { 
     return null; 
    } 
} 

class SturdyFactoryBuilding ... { 
    // ... 
    @Override 
    Factory adaptToFactory() { 
     return this; 
    } 
} 

De même pour ShakyFactoryBuilding.

Ensuite, vous pouvez écrire

Factory f = building.adaptToFactory(); 
if (f != null) 
    f.printFactoryOutput(); 

Plus adaptateur général

Si vous faites beaucoup de ce genre de chose, vous pourriez en faire un modèle que vous appliquez chaque fois que nécessaire. (Eclipse, par exemple, utilise des adaptateurs dans tous les sens.)

interface Adaptable { 
    <T> T adapt(Class<T> clazz); 
} 

class Building implements Adaptable { 
    // ... 
    @Override 
    <T> T adapt(Class<T> clazz) { 
     if (clazz.isInstance(this)) { 
      return clazz.cast(this); 
     } 
     return null; 
    } 
} 

Ensuite, vous écririez

Factory f = building.adapt(Factory.class); 
if (f != null) 
    f.printFactoryOutput(); 

Il y a encore plus d'endroits pour aller avec, mais cela est suffisant pour cette question, je pense.

+0

Merci, malheureusement, il n'y a aucune option pour re-concevoir le système. Mais puisque l'interface n'a qu'une poignée de méthodes, la manière décrite par Fildor ou la méthode 'adaptToFactory' semble raisonnable. – Bluefarmer