【问题标题】:instanceof vs isAnX()instanceof vs isAnX()
【发布时间】:2011-08-28 19:42:09
【问题描述】:

在 java 中,我正在编写一些 DTO 对象,它们都继承自 AllocationDTO
然后将这些对象的列表传递到 DAO 对象中以保存到数据库中。

根据要保存AllocationDTO 的哪个子类型,保存逻辑会发生变化(例如,要保存到数据库中的哪个表等)

我发现自己使用这样的代码:

for (AllocationDTO x : listOfAllocationDtos) {
    if (x instanceof ManagerAllocationDTO) {
         Manager m = (x(ManagerAllocationDTO)).getManager();
         // save manager etc to managerallocs
    } else if (x.getId() == AllocationDTO.TYPE_SPECIAL1) {
         // save to specialAlloc1 table
    } else if (x.getId() == AllocationDTO.TYPE_SPECIAL2) {
         // save to specialAlloc2 table
    }
}

ManagerAllocationDTO 有一个额外的字段将分配与经理相关联,但对于 specialalloc1/2 的情况,我没有创建子类型,因为数据的唯一区别是它保存到的表。

我的问题是一个软设计问题 - 这是最好的方法吗?

【问题讨论】:

  • 只是对您的代码的评论:您确实应该使用equals 方法而不是== 来比较您的字符串。尤其是在使用数据库时。
  • 不太确定像 "(x.getId() == "specialAlloc2")" 这样的代码 - 你真的对对象相等感兴趣还是你真的应该使用 "x.getId().equals ("specialAlloc2")" ?
  • "specialAlloc2" 是一个常数,所以我认为在这种情况下对象相等性测试是可以的。我在发布此内容后立即更改了代码以引用所述内容,并意识到你们两个刚刚评论的内容相同。我已编辑问题以反映我的更改。你同意吗?

标签: java design-patterns dao dto


【解决方案1】:

在没有instanceOf 和 if-else-cascade 的情况下分隔不同实例的一种方法是使用Visitor Design pattern

  • 新接口:AllocationVisitor 为 AllocationDTO 的每个具体子类提供一个方法:

    • 访问(TYPE_SPCIAL1 dto)
    • 访问(TYPE_SPCIAL2 dto)
  • AllocationDTO: abstract void acceptVisitor(AllocationVisitor visitor)

  • AllocationDTO 的每个 concreate 子类都以这种方式实现 acceptVisitor(): void acceptVisitor(AllocationVisitor visitor){visit(this);} //编译时类型选择正确的访问方式。
  • 您的 DTO 实现了 AllocationVisitor 接口(带有一个内部类),创建它的一个实例,并将其传递给 listOfAllocationDtos 的元素。

道:

AllocationVisitor saveVisitor = new AllocationVisitor() {
  visit(TYPE_SPCIAL1 dto) {//what ever you need}
  visit(TYPE_SPCIAL2 dto) {//what ever TYPE_SPCIAL2 needs}
}
for (AllocationDTO x : listOfAllocationDtos) {
  x.visit(saveVisitor);
}

【讨论】:

  • 这看起来我必须将保存逻辑添加到 DTO。我不喜欢这个想法,因为这个想法是 DTO 基本上是一个数据容器,不知道它是如何持久化/传输的等。DAO 应该知道 DTO,但不是相反。我是否正确理解了访问者模式?
  • 不,如果按照模式,那么DTO只有一个类似回调的方法,逻辑属于DAO
  • @Ben Page:我已经扩展了我的答案来解释访问者模式。这种模式是 GOF 书中最复杂的(并且从静态结构的角度很难理解)之一。但是即使你不使用它来处理这种情况,你也应该看看他的力量全模式。 -- 您可以在任何需要案例的地方使用它,具体取决于类型。那么如果你添加一个新的类型,你永远不会忘记“扩展案例”,因为编译器会检查它。
  • 感谢您的解释。我了解它的工作原理,并且(希望)能够实现它。
猜你喜欢
  • 2018-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-22
  • 2021-03-03
  • 1970-01-01
相关资源
最近更新 更多