3

我正在编写一个对象转换类,用于将域层对象转换为 UI 对象,反之亦然。问题是我的 UI 对象被组织成一个层次结构,因此我的对象转换类包含“instanceof”语句。这里有一种明确的代码气味,但我不确定解决方案是什么。

所以我的 UI 层次结构包含一个 RuleDTO,如下所示:

public class RuleDTO {
    protected long ruleID;
    protected long rowID;   
    protected AttributeDTO leftCondition;
    protected AttributeDTO rightCondition;
    protected OperationTypeDTO operationType; 
    protected boolean isActive;     
    // etc...
}

然后,我的 RuleDTO 可以由 AssignmentRuleDTO 子类化,如下所示:

public class AssignmentRuleDTO extends RuleDTO {
    protected String assignedToTeam;
    protected String assignmentOperator;        
    // etc...
}

RuleDTO 也可以由 EvaluationRuleDTO 子类化:

public class EvaluationRuleDTO extends RuleDTO {
    protected String successAction;
    protected String failureAction;
    // etc...
}

然后在我的 ObjectConversionHelper 类中遇到了问题,该类包含以下类型的逻辑:

{
    // Perform logic common to RuleDTO such as setting ruleID, isActive etc
    if(ruleDTO instanceof AssignmentRuleDTO) {
        // Set assignedToTeam and assignmentOperator etc
    }
    else if (ruleDTO instanceOf EvaluationRuleDTO) {
        // Set successAction and failureAction etc  
    }
}

相反,这里有什么好的解决方案?我已经阅读了访问者模式,但不确定它如何应用在这里。

谢谢

4

7 回答 7

3

你的RuleDTO类应该有一个被调用的方法setStuff()或类似的东西。

然后你覆盖它AssignmentRuleDTOEvaluationRuleDTO设置相关字段。

这样你ObjectConversionHelper就可以打电话

ruleDTO.setStuff();
于 2012-07-18T20:28:35.790 回答
3

我认为在这里使用访问者模式是一种合理的方法。所以你会有访客界面

interface RuleDTO {
    void visit(RuleDTO theRule);
    void visit(EvaluationRuleDTO theEval);
    void visit(AssignmentRuleDTO theAssign);
    ... and so on ...
}

你会为这些具体的类添加一个方法来处理双重调度

public void accept(RuleDTOVisitor theVisitor) {
    theVisitor.visit(this);
}

最后,您将创建一些实现访问者的类,例如 SettingPropertiesVisitor,并且对于每个方法,您可以执行实现,其中每个对象的适当字段都根据您的应用程序要求设置。

那么使用它

aRuleDTO.accept(new SettingPropertiesVisitor());

这样,将为每种类型调用适当的访问者方法,然后在 SettingPropertiesVisitor 的方法中,您可以进行适当的分配。这将绕过 instanceof 检查,并将 setter 逻辑与对象分离。

当然,如果这是您创建的唯一访问者,这可能是矫枉过正,在这种情况下,instanceof 不像杀死小猫。但这里明显的缺点是每次扩展 API 时,都需要修改访问者界面,然后可能所有的具体访问者都支持新方法。

于 2012-07-18T20:55:37.977 回答
2

恕我直言,访客在这里看起来有点矫枉过正。

对象图没有迭代。
不需要双重派送。

记住 KISS 和 YAGNI。只需添加一个抽象方法或保持原样。
您以后总是可以重构 - 假设您已经进行了测试;)

于 2012-07-18T23:28:38.440 回答
1

在您的情况下,可以通过在 RuleDTO 中编写 convertToOtherClass 方法来应用访问者模式,然后由其子类覆盖该方法。然后,在您的对象转换类中,您将拥有一个类似于 convertRuleDTO 的方法(在 RuleDTO 的 convertToOtherClass 方法中调用),该方法执行相关代码,确保它在没有子类的 RuleDTO 实例上运行,因为否则子类将覆盖 convertToOtherClass 方法。

于 2012-07-18T20:29:30.000 回答
0

去掉“其他”……有什么问题?

于 2012-07-18T20:28:13.577 回答
0

有几种可行的方法。我会考虑的两个是使用所有类都实现的接口或使用与不同类对应的枚举。

如果你有一个接口(让我们称之为它public interface DTO,你可以在其中调用一个方法签名setFields()或类似的东西,每个实现类都必须实现。然后,通过多态的魔力,你现在可以将所有对象视为DTO使用类型转换并调用setFields()它们而不用担心实际的对象是什么。setFields()每个单独的类中的方法会为你处理它。

或者,您可以创建一个本质上是每个类的 ID 的枚举,并使每个类具有该类型的全局变量(包含 getter 和 setter)以识别它。这是一个有点“hacky”的解决方法,但仍然是可行的。

于 2012-07-18T20:51:11.097 回答
0

为每个 DTO 类创建一个 ObjectConversionHelper 类怎么样?它们中的每一个都可以不同地实现一个通用的转换接口,调用继承的成员等。然后你可以利用一些对象创建工厂来为 DTO 创建相关的 Helper,反之亦然(即使用反射机制)。

于 2012-07-20T08:49:03.357 回答