【问题标题】:Forced Downcasting in JavaJava中的强制向下转换
【发布时间】:2010-12-03 15:56:31
【问题描述】:

我想对一个无法向下转换的对象强制进行向下转换,并且想知道正确的方法是什么。 用例是我有一个检查的规则列表以及生成失败规则列表的内容。失败的规则是规则的子类。但是像
FailedRule failedRule = (FailedRule) rule;

将失败,因为规则对象不是 FailedRule 的实例

为了解决这个问题,我实例化了一个克隆;
FailedRule failedRule = new FailedRule (rule);

我的 FailedRule 类看起来像这样

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());
   ..

有没有更简单的方法来做到这一点? 回答我自己,设计有缺陷,代码应该是:

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

【问题讨论】:

  • 我想知道您最终是如何对无法向下转换的对象强制向下转换。向我们解释您真正想做的事情。
  • 我虽然做到了:-)。我遍历规则列表并返回失败的规则列表。检查过程会根据规则返回大量信息,为什么以及何时以及如何失败。马克的回答是正确的,我的设计是错误的,我不能说失败的规则是“规则”。它'有一个'规则。我已经编辑了问题,因为我无法将代码放入这些 cmets

标签: java class object casting downcast


【解决方案1】:

这可能是您的继承层次结构设计薄弱的症状。您正在尝试通过继承引入属性的可变性(如果FailedRuleFailedRule 的实例,则Rule 已“失败”)。继承对于那种事情来说并不是很好。

我会说你应该使用组合(FailedRule 有一个规则作为源)或者 failed 应该是 Rule 实例的布尔属性。

【讨论】:

  • 好的,所以 FailedRule 不是规则的子类,因为失败的规则不是规则。 FailedRule 类是具有规则作为属性的失败规则; failedRule.setRule(规则); failedRule.setReason(reason) 等
  • @Meindert:我不确定这是否是一个好方法,因为我没有太多上下文。 FailedRule 甚至提供了哪些额外的方面? 规则失败后,其内部状态有何变化? 如果是我,我会说“如果规则出现在失败规则列表中,则该规则失败”。将规则的概念与其执行结果分开似乎是合乎逻辑的。就像您不会将汽车在最后一场比赛中得分的位置存储在汽车本身中一样;你会有一个引用汽车的RaceRecord
  • 如果组合是要走的路,我会考虑重命名FailedRule。这不是规则,是吗?这只是规则失败的上下文/记录。我会称它为RuleFailure 或类似的名称。
  • 嗯,在用户看来,这是一个失败的规则列表......但你是对的,我将失败的规则存储在一个名为 RuleFail 的表中。
【解决方案2】:

使用将任何规则转换为FailedRule的方法:

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

(如果规则已经是FailedRule,则强制转换并返回,否则使用它构造FailedRule

【讨论】:

    【解决方案3】:

    您所拥有的似乎是一个合理的解决方案。如果任何规则可能是失败的规则,则将其建模为Rule.isFailed() 可能更合适。

    编辑: 失败听起来很像一种状态,而不是规则的变体。如果是这样的话,Rule.isFailed() 也会更喜欢。如果存在确实不会失败的规则,我们可以将其建模为:

               Rule
             /      \
             |       \
        FailableRule  RuleC
         /     |   
     RuleA    RuleB
    

    嗯... failable 规则实际上是 fallible 规则吗? Gaawgh...语言学。

    【讨论】:

    • 这是个好主意,即使该方法仅在 Rule 上包含 return false; 并且在 FailedRulereturn true; 中被覆盖。
    • 其实只是想到了另一件事。 Failed 听起来很像规则的状态,而不是规则的变体。如果是这样的话,FailedRule 不是很好哦。
    • 不过,问题是关于向下转型,而不是评估他的设计选择。
    • 暂时不同意。 SO 中的很大一部分问题显然与人们不了解技术或他们正在处理的问题有关。如果我看到明显的遗漏或有问题的想法,我显然会尝试帮助了解整个情况,尽管问题是关于特定问题的问题。这就是用户应该提供尽可能多的上下文的原因。
    • 提交此问题的用户可能永远不会回来查看它。大多数来这里的人都会寻找垂头丧气的东西。因此,我们应该专注于回答问题,而不是评估没有费心回来澄清的用户的体验。
    【解决方案4】:

    没有更简单的方法。你这样做是正确的。

    很多时候,我会写一个私有方法,像这样:

    私人无效copyFromRule(规则其他规则){ this.setRuleCode(otherRule.getRuleCode()); this.setType(otherRule.getType()); ... }

    这样,我可以在这样的构造函数中调用它,如果我需要定义一个,也可以在 clone() 方法中调用它。

    另一点是要知道你是在打电话给super.setRuleCode 还是this.setRuleCode。显然,这两件事根据FailedRule 是否重新定义setRuleCode 来做不同的事情。

    【讨论】:

      【解决方案5】:

      你不能像这样将一个类转换为一个子类。它没有任何意义,因为它没有来自子类的任何方法或变量。你做对的方式。

      【讨论】:

        【解决方案6】:

        你这样做的方式是正确的。我必须添加的唯一注释是将复制代码下移到 Rule 本身。

        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());
           ...
        

        【讨论】:

        • 谢谢,这是一种更简洁的克隆方式。我正在寻找一种“自动克隆”方法,它将 ruleToCopy 的所有属性放入“this”中。但我接受马克的回答是我的设计有缺陷
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-17
        • 1970-01-01
        • 1970-01-01
        • 2017-03-16
        • 2011-02-12
        相关资源
        最近更新 更多