2010-12-03 48 views
3

Je veux forcer un downcast sur un objet qui ne peut pas être lancé et je me demandais quelle serait la bonne approche. Le cas d'utilisation est que j'ai une liste de règles qui sont vérifiées et ce qui générera une liste de règles échouées. Une règle en échec est une sous-classe d'une règle. Mais descente comme
FailedRule failedRule = (FailedRule) règle;Downcasting forcé en Java

échouera parce que l'objet de la règle n'est pas une FailedRule instanceof

Pour contourner ce que j'instancier un clone;
FailedRule failedRule = new FailedRule (règle);

et ma classe FailedRule ressemble à ceci

public class FailedRule extends Rule{ 

/* 
*force a down cast from Rule to FailedRule through cloning 
*/ 
public FailedRule (Rule upcast){ 
    super.setRuleCode(upcast.getRuleCode()); 
    super.setType(upcast.getType()); 
    .. 

Est-il possible de faire plus facile cela? Pour me répondre, la conception est défectueuse, le code doit être:

public class FailedRule{ 
    private Rule rule; 
    .. 
    public setRule(Rule rule){ 
    .. 
+0

Je me demande comment vous finissez par devoir baisser sur un objet qui ne peut pas être coulé. Explique-nous ce que tu veux vraiment faire. –

+0

Je pensais avoir fait :-). Je parcours une liste de règles et retourne une liste de règles qui ont échoué. Le processus de vérification renvoie une bonne quantité d'informations par règle, pourquoi et quand et comment elle a échoué. La réponse de Mark est correcte, mon design est faux, je ne peux pas dire qu'une règle qui a échoué est une règle. Il a une «règle». J'ai édité la question parce que je ne peux pas mettre le code dans ces commentaires – Meindert

Répondre

2

Ceci est probablement un symptôme que votre hiérarchie d'héritage est faiblement conçue. Vous essayez d'introduire la mutabilité des attributs via l'héritage (un Rule a "échoué" s'il s'agit d'une instance de FailedRule). L'héritage n'est pas vraiment bon pour ce genre de chose.

Je dirais que vous devriez utiliser la composition (un FailedRule a une règle comme source) ou que failed devrait être un attribut booléen d'une instance de Rule.

+0

+1 c'est un problème de conception. –

+0

Ok, donc FailedRule n'est pas une sous-classe d'une règle car une règle en échec n'est pas une règle. Une classe FailedRule est une règle ayant échoué qui a une règle en tant que propriété; failedRule.setRule (règle); failedRule.setReason (raison) etc – Meindert

+0

@Meindert: Je ne suis pas sûr que ce soit une bonne approche ou non, puisque je n'ai pas beaucoup de contexte. Quels aspects supplémentaires 'FailedRule' peut-il même fournir? * Quels changements sur l'état interne d'une règle maintenant qu'elle a échoué? * Si c'était moi, je dirais "une règle a échoué si elle apparaît dans la liste des règles échouées." Il semble logique de séparer le concept de la règle des résultats de son exécution. Tout comme vous ne stockez pas la place qu'une voiture a marqué dans sa dernière course dans la voiture elle-même; vous auriez un 'RaceRecord' qui fait référence à la voiture. –

0

Il n'y a pas moyen plus facile. Vous faites cela correctement.

Plusieurs fois, je vais écrire une méthode privée, quelque chose comme ceci:

 
private void copyFromRule(Rule otherRule) { 
    this.setRuleCode(otherRule.getRuleCode()); 
    this.setType(otherRule.getType()); 
    ... 
} 

De cette façon, je peux l'appeler dans un constructeur comme celui-ci, et aussi dans une méthode clone() si je dois définir un.

Un autre point est de savoir si vous appelez super.setRuleCode ou this.setRuleCode. Évidemment, ces deux choses font des choses différentes selon si FailedRule redéfinit setRuleCode.

+0

-1, le problème est de conception. Regardez la réponse de Mark Peters. –

1

Ce que vous avez ressemble à une solution raisonnable. Si une règle peut potentiellement être une règle ayant échoué, il peut être plus approprié de la modéliser comme Rule.isFailed().

Edit:Failed ressemble beaucoup à un état, pas une variante d'une règle. Si tel est le cas Rule.isFailed() serait également préférable. S'il y a des règles qui vraiment ne manquent pas, nous pourrions modèle comme:

  Rule 
     / \ 
     |  \ 
    FailableRule RuleC 
    / | 
RuleA RuleB 

Hmm ... est une règle failable fait une règle faillible ? Gaawgh ... linguistique.

+0

C'est une bonne idée, même si la méthode ne contient que 'return false;' sur 'Rule' et est remplacée dans' FailedRule' par 'return true;'. –

+0

En fait, juste pensé à autre chose. * Echec * ressemble beaucoup à un état de règle, pas à une variante de règle. Si tel est le cas, 'FailedRule' n'est pas génial. –

+0

La question, cependant, est sur le downcasting, ne pas évaluer ses choix de conception. –

0

Vous ne pouvez pas convertir une classe en une sous-classe comme celle-ci. Cela n'a pas de sens car il n'aurait aucune des méthodes ou variables de la sous-classe. La façon dont vous le faites bien.

0

La façon dont vous le faites est correcte. Le seul commentaire que je dois ajouter est de déplacer le code de la copie vers la règle elle-même.

public class FailedRule extends Rule{ 

/* 
*force a down cast from Rule to FailedRule through cloning 
*/ 
public FailedRule (Rule upcast){ 
    super(upcast); 
    //init FailedRule fields to defaults 
} 
} 

public class Rule { 

publiic Rule(Rule ruleToCopy) { 
    //or even use the fields themselves. 
    this.setRuleCode(ruleToCopy.getRuleCode()); 
    this.setType(ruleToCopy.getType()); 
    ... 
+0

merci, c'est une façon plus propre de cloner.Je cherchais une méthode de 'clonage automatique' qui placerait toutes les propriétés de ruleToCopy dans 'this'. Mais je vais avec la réponse de la marque que mon design est défectueux – Meindert

2

Utilisez une méthode qui permet de convertir une règle à un FailedRule:

public static FailedRule asFailedRule(Rule rule){ 
    return (rule instanceof FailedRule) 
    ? (FailedRule) rule 
    : new FailedRule(rule) 
} 

(Si la règle est déjà un FailedRule, acteurs et le retourner, sinon utiliser pour construire un FailedRule)