我应该为数据传输对象创建接口吗?


19

为数据传输对象创建接口是一个好主意还是一个坏主意?假定对象通常是可变的。

尽管我的示例是使用Java编写的,但它应适用于具有类似概念的任何其他语言。

interface DataTransferObject  {
    String getName();
    void setName(String name);
}

class RealDataTransferObject  implements DataTransferObject {

    String name;
    String getName() {
        return name;
    } 
    void setName(String name) {
        this.name = name;
    }
}

当然,这是一个简化的示例,在现实生活中可能会有更多的领域。

Answers:


24

普遍的回答是“ 否”,因为在没有特定的具体原因的情况下,您永远不应添加代码,并且此类接口也没有普遍的理由。

话虽如此,有时可能有充分的理由。但是在所有情况下,这些接口都是局部的,只覆盖了多个类共享的一个或几个属性,这些类我想在不给它们一个公共超类的情况下多态地使用。典型的候选对象是Id要在某种注册表中使用的属性,还是Name要显示给用户的属性。但是,在希望某些代码处理具有X的所有内容的任何情况下,它都很有用-只需创建一个XSource包含getX(和(仅在需要时setX)方法)接口即可。

但是每个模型类都有一个单独的接口,包含所有属性吗?我无法想象这样做的充分理由。一个不好的原因是设计不好的框架需要它。如果我没记错的话,实体EJB就是这样做的。值得庆幸的是,它们是如此糟糕,以至于它们从EJB 3.0开始就从未获得太多关注,并且已被弃用

旁注:请避免使用术语“值对象”来描述仅具有琐碎的getter和setter的Java Bean-它与更常见的值对象定义冲突,因为后者没有身份通常是不可变的。更好的术语是DTO或模型类-尽管在后一种情况下,请注意贫血域模型被视为反模式。


3
“贫血领域模型被认为是一种反模式”-马丁·福勒(Martin Fowler)在PEAA中承认,他知道以这种方式工作了数十年的人们“非常成功”。因此,我建议不要使用反模式,而应该使用Fowler不太喜欢的方式。但是,好的答案是+1。
pdr 2013年

4
@pdr:Fowler可能是创造了这个词,但他绝不是唯一认为它们是反模式的人。我认为没有任何真正了解OO的人认为将特定于域的逻辑排除在域模型之外是个好主意。
Michael Borgwardt

感谢术语更正,DTO是昨晚我一直在寻找的单词,但我一生都记不清了。通过更改名称,使设计更有意义。
阿基米德·特拉哈诺

@pdr我认为最好的表达方式是在OO编程中它是一种反模式。还有很多其他范例都可以很好地使用它,甚至可以使用OO语言成功地进行这种工作(它并不是特别面向对象的)。
Daniel B

3
@MichaelBorgwardt:我同意,他并不孤单。但是不同意的人也没有。如果您说“有些人认为贫血领域模型是一种反模式”,那我什么也没说。坦率地说,如果没有最后一段,我认为您的整个答案会更好。上半年会有更好的评论。后半部分对此问题无能为力。
pdr

2

创建界面是可以的,但不是您的示例的工作方式。您应该从界面中删除设置器,这样就可以了:

interface ValueObject {
  String getName();
};

这允许它的许多不同实现,例如可以从数据库中获取名称...设置器应位于不同的接口中。


2

接口定义了实现接口的类及其客户端之间的协定。它们被用作抽象机制,以便客户端可以操纵“具有给定行为的东西”。

因此,对“我应该创建并使用此接口?”这个问题的一般答案是什么?是:是的,如果您可以关联一个与您的客户在语义上相关的(单个)概念。

例如,Comparable是一个很好的接口,因为它解释说可以通过事物的一种方法来比较事物,并且作为客户端,我对处理可比较的对象(例如,对它们进行排序)感兴趣。相反,如果您承认酷对象没有特定的行为,那么CoolStuff并不是一个很好的界面(实际上,您可以想象一个处理酷对象的软件有意义,因为它们具有诸如beCool之类的常见行为。方法)。

在您的特定情况下,我相信您的界面是无用的。谁来使用它?如何使用?何时使用?您不能为每个可变值创建一个接口。因此,问问自己,方法背后的相关和有趣的属性是什么。

如果您要处理的对象具有可通过两种方法访问其所有可变值的对象,请查看Java bean的概念以及强制类采用其约定的方式。


2

正如迈克尔所说,除非您有特定的需求,否则请不要添加接口。

测试是一个很好的例子。尽管我更喜欢使用真正的协作者(如果您称它们为“值对象”),但是对于真正的单元测试隔离,您可能需要创建一个假对象进行测试,在这种情况下,接口非常有帮助。


1
多年来,使用模拟框架都不需要接口。
Michael Borgwardt

听起来您是在提倡猴子修补。我在C#中和Moles一起走过那条路,这并不漂亮。如果可能,最好让您的合作者通过。
jhewlett

1
尽管我使用的两个模拟框架Mockito和easyMock在使它们不变时不能模拟最终类。
阿基米德·

1

如果希望此对象将来进行某种形式的字段验证,则应在早期将其封装。


0

“值对象的接口”是我用来调用访问器的接口。

我经历了有关访问者需求的不同政策。有些人主张尽可能的多,另一些则禁止然后减少编写的代码量。

访问者(或直接使用价值)的一些口供如下:

  • 访问器允许以后更改值的存储方式
  • 访问器允许在您要调试软件时添加访问日志(在单个方法中添加日志调用时,您将捕获每个值更改)
  • 访问器更符合对象编程,每个变量都由方法封装
  • 访问器降低了代码的表达能力(更多SLOC可获得相同结果)
  • 存取器需要一些CPU

我个人提倡减少访问器的数量,并在以后希望设置器(setName)变得不仅仅是简单的影响时使用它们。


0

这种价值对象是相当低的水平。我建议朝两个方向之一推动它:(1)使值对象不可变,即像真实值一样;或者,(2)将可变性提升到面向领域的更高级别的业务功能,这意味着我们应该公开接口与域相关的功能单元有关。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.