2010-05-27 3 views
0

D'abord, je suis désolé pour le titre de la question, mais je ne peux pas penser à un meilleur pour décrire mon problème. N'hésitez pas à le changer :)Quelle est ma meilleure approche sur cette hiérarchie simple Java Problem?

Disons que j'ai cette classe abstraite Box qui implémente un couple de constructeurs, méthodes et autres sur certaines variables privées. Ensuite, j'ai quelques sous-classes comme BoxA et BoxB. Les deux implémentent des choses supplémentaires. Maintenant j'ai une autre classe abstraite Shape et quelques sous-classes comme Square et Circle.

Pour les deux BoxA et BoxB je dois avoir une liste des objets Shape mais je dois vous assurer que seuls Square objets entrent dans BoxA « liste et de seulement Circle objets entrent dans BoxB » liste de.

Pour cette liste (sur chaque boîte), je dois avoir une méthode get() et set() et aussi une des méthodes addShape() et removeShape().

Une autre chose importante à savoir est que pour chaque boîte créée, soit BoxA ou BoxB, chaque liste Shape est exactement la même. Disons que je crée une liste de Square nommé ls et deux objets BoxA nommés boxA1 et boxA2. Quoi qu'il en soit, boxA1 et boxA2 doivent avoir la même liste ls.

Ceci est mon idée:

public abstract class Box { 
    // private instance variables 

    public Box() { 
     // constructor stuff 
    } 

    // public instance methods 
} 

public class BoxA extends Box { 
    // private instance variables 

    private static List<Shape> list; 

    public BoxA() { 
     // constructor stuff 
    } 

    // public instance methods 

    public static List<Square> getList() { 
     List<Square> aux = new ArrayList<Square>(); 

     for(Square s : list.values()) { 
      aux.add(s.clone()); // I know what I'm doing with this clone, don't worry about it 
     } 

     return aux; 
    } 

    public static void setList(List<Square> newList) { 
     list = new ArrayList<Square>(newList); 
    } 

    public static void addShape(Square s) { 
     list.add(s); 
    } 

    public static void removeShape(Square s) { 
     list.remove(list.indexOf(s)); 
    } 
} 

Comme la liste doit être la même pour ce type d'objet, je déclarai comme static et toutes les méthodes qui fonctionnent avec cette liste sont également static. Maintenant, pour BoxB la classe serait presque la même chose concernant la liste des choses. Je voudrais seulement remplacer Square par Triangle et le problème a été résolu. Ainsi, pour chaque objet BoxA créé, la liste ne serait qu'une seule et même chose. La même chose se produirait pour chaque objet créé, mais avec un type différent de liste bien sûr.

Alors, quel est mon problème? Eh bien, je n'aime pas le code ... Les méthodes getList(), setList(), addShape() et removeShape() sont essentiellement répétées pour BoxA et BoxB, seul le type d'objets que la liste tiendra est différent. Je voulais éviter, d'une façon ou d'une autre, toutes ces méthodes de "duplication".

Je ne peux pas penser à la façon de le faire dans la super classe Box à la place. Essayer de le faire aussi statiquement, en utilisant Shape au lieu de Square ou Triangle, ne fonctionnerait pas parce que la liste ne serait qu'un pour tous les objets BoxA et BoxB, et je n'ai besoin que d'un seul mais pour chaque sous-classe de Box.

Comment pourrais-je faire différemment et mieux? P.S: Je ne peux pas décrire mon vrai exemple parce que je ne connais pas les mots corrects en anglais pour ce que je fais, donc j'ai juste utilisé un exemple de boîte et de formes, mais c'est fondamentalement la même chose.

+0

J'avais suggéré de faire un type générique Box, mais vous ne pouvez pas utiliser des méthodes statiques génériques. – Powerlord

+0

Si vous n'étiez pas statique, vous pourriez utiliser des génériques. Faire une usine pour produire des boîtes et passer la liste sur le constructeur de la boîte. – Beothorn

+0

Cela créerait toujours une liste par boîte et je ne le veux pas. N'est-ce pas? De toute façon, je n'ai pas appris une telle chose, donc je ne suis pas censé l'utiliser. –

Répondre

1

Vous pouvez essayer quelque chose comme:

abstract class Box<E extends Shape> { 

    abstract protected List<E> getList(); 

    abstract protected void setList(List<E> list); 

    protected static <T extends Shape> List<T> getCommon(Box<T> box) { 
     List<T> aux = new ArrayList<T>(); 
     for (T s : box.getList()) { 
      aux.add((T) s.clone()); 
     } 
     return aux; 
    } 

    protected static <T extends Shape> void setCommon(Box<T> box, List<T> newList) { 
     // do something on newList here if needed as common functionality 
     box.setList(new ArrayList<T>(newList)); 
    } 
} 
class BoxA extends Box<Square> { 
    private static List<Square> list; 

    @Override 
    protected List<Square> getList() { 
     return list; 
    } 

    @Override 
    protected void setList(List<Square> list) { 
     this.list = list; 
    } 

    public static List<Square> get() { 
     return getCommon(new BoxA()); 
    } 

    public static void set(List<Square> newList) { 
     setCommon(new BoxA(), newList); 
    } 
} 

Il est un peu hackish mais il vous permet d'utiliser la classe mère pour occuper certaines fonctions communes. Vous devrez toujours avoir les méthodes finales dans les classes enfant, mais tout ce que vous faites en eux est d'appeler les méthodes parent en leur donnant une nouvelle instance de votre classe actuelle, de sorte que la méthode parent puisse en déduire le type générique. Notez que getList() et setList() ne sont pas statiques pour leur permettre d'avoir le paramètre type de Box, et ils sont protégés donc ils ne sont pas visibles à l'extérieur. Ils agissent en tant que setter getter pour une variable statique privée (que chaque classe d'extension devrait avoir), pour permettre l'accès au parent pour faire le travail commun sur une variable qui appartient aux enfants.

pour permettre l'accès à la liste statique get() et set() utilisation de la méthode new BoxA() (ou new BoxB()), en passant aussi le paramètre de type au parent. Puisque la liste est statique, peu importe quelle instance la renvoie. Les méthodes communes ont leur propre paramètre de type qui n'est pas celui que possède la classe; vous pouvez en fait appeler getCommon(new BoxB()) à partir de BoxA, donc ce sera votre travail pour vous assurer que vous appelez le bon.

Questions connexes