耦合:使用原始类型,接口或具体对象作为参数?

时间:2012-11-23 10:21:11

标签: interface dependencies coupling oop

首先让我说我对OO模式,实践,清洁代码等有经验。 我实际上正在学习所有这些技巧。

最松散耦合的方式是使用原始类型来构造新对象或执行方法,但我认为这不可行,这是正确的吗? 因为它更容易出错。我可以放弃让我们说代表不存在的ID的整数。如果我要使用一个对象,我实际上知道它有有效的数据,否则该对象将不会被创建(异常)或者将处于无效状态,我必须检查它。

This article说使用具体对象是邪恶的,相反我应该交出他们的界面(我猜你们都知道)。 对具体类型(不是接口)的更改将导致依赖类型“分解”。在所有情况下都是这样吗?对于封闭的单一项目环境,这也是如此吗? 我只会理解,如果接口是 - 一旦写入 - 不可触及,再也不会被修改/重构。

3 个答案:

答案 0 :(得分:2)

您应该在需要时使用所有内容。只有在有意义的情况下才使用原语。与具体类型相同。确实,选择“耦合”更好。然而,在许多情况下,你不会拥有一个,而你不需要一个。您可以从您正在使用的所有对象中提取接口,但如果您没有真正的理由这样做(多态),那将毫无意义。

你必须思考。您可以开始使用具体类型,但是您会发现您确实需要抽象而不是具体类型(例如,如果您知道存储可以更改,则抽象存储是一种非常常见的情况)。对象可以依赖于数据库抽象(抽象类或接口),而不依赖于Mysql Database对象,它允许您切换任何实现(Mysql,MMSql甚至NoSql)。但是,如果您要编写一个只使用mysql的小应用程序,请直接使用具体类型。

您可能还需要提取接口和测试的另一个原因。当然,仅当具体类型将用作依赖项并且具有足够复杂的行为时才提取接口。如果一个依赖只是一个简单的DTO(数据传输对象),你就不需要抽象它。

大多数这些东西都带有经验,但是拇指规则从具体类型开始,然后在需要时抽象它。如果对象已经实现了包含您想要的功能的接口,则直接使用该接口。

答案 1 :(得分:2)

我想这个问题引发了很多问题。我会尽量让事情尽可能短:

  

我可以放弃让我们说代表简单的Ids的整数   不存在。

从我的观点来看,程序是代表你的问题领域的(计算)模型(类比可以由物理学家或天文学家编写方程式来表示现象)。使用对象建模时,您正在使用某些特定规则创建该域的表示。所以,回到你的问题,你可以用概念表示概念上带有整数的ID,但是你的问题域中会有一个未正确表示的概念(因为,例如,有些整数不是有效的ID )。此外,除了概念问题,问题是你不能添加(并因此委托)一个整数的新行为,如果你可以(例如在Smalltalk中,一切都是一个对象,你可以扩展任何类),这也是错误的从建模的角度来看。作为一般的经验法则,当我必须在不应该具有给定责任的对象中编写行为时,我会考虑缺少抽象的模型。在这种情况下,就像拥有Util类,类方法isValidId

  

如果我要使用一个对象,我实际上知道有有效的数据   否则就不会创建对象(异常)或   将处于无效状态,我必须检查。

同意100%。我写了一篇couple of articles关于这个你可能觉得有用的文章(免责声明:我在Quanbit Research工作)

  

这篇文章说使用具体对象是邪恶的,   相反,我应该交出他们的接口(众所周知,我   猜测)。具体类型(不是界面)的更改会导致   依赖类型为“崩溃”。在所有情况下都是这样吗?

涉及对象,类型和接口的故事很长。总而言之,理想情况下,您应该针对接口而不是具体类进行编程,因为(理论上)您应该只关心给定对象(例如参数)实现具有预定义语义的一组消息。但是,如果你走这条路,在实践中你会看到一个类通常实现多个接口,并且让所有接口与类同步的簿记是令人望而却步的。我通常使用动态类型的语言,所以在大多数情况下这对我来说不是问题,但如果我必须使用静态类型语言,当系统必须与项目外部的代码形式接口时,我会使用接口或在模块之间的API中。换句话说,我会尝试降低系统“边界”中的耦合。

  

对于封闭的单一项目环境,这也是如此吗?我会   只知道,如果接口 - 一旦写入 - 不可触及   永远不会被修改/重构。

我不得不在这里不同意。作为计算模型的程序反映了我们在问题域的给定时间点所知道的内容。因此,我们对它的研究越多,我们就越了解它。编程涉及学习,当我们学习时,我们更好地理解事物;因此我们的模型改变了随着我们的模型发生变化,我们用来表示它们的元素也会发生变化(如类或接口)。随着时间的推移,您将看到您的模型变得更加强大,概念变化将变慢,并且在某些时候您将拥有稳定的模型。但变化是因素,你应该期待的事情:)。

HTH

答案 2 :(得分:2)

我认为答案(通常是这样)是'它取决于'。决策受以下因素影响:

  1. 您正在使用哪些类型的对象?域对象(表示业务域中的概念)或服务(例如提供查找或保存操作)。

  2. 您的申请有多大/多复杂?

  3. 你拥有'你正在使用的所有物品吗?您正在使用的对象是否可能被您无法控制的其他人更改?

  4. 对于足以证明Domain Model合理的项目,我想使用以下设置:

    1. 包含'finder'服务对象的Data Access Layer,它包含ids和返回域对象,以及“保存”带有域对象的服务对象。

    2. 包含域对象的域模型,这些域对象仅在其方法中使用其他域对象。

    3. 带有ID的Service Layer,使用数据访问层检索域对象,触发域模型中的域操作,然后使用数据访问层保存更改。

      < / LI>
    4. 使用服务层的一个或多个UI图层,提供ID。

    5. 我将Service对象放在接口后面的数据访问层和服务层中,因为我希望该选项可以在单元测试中轻松模拟这些组件。我通常不会为我的域对象创建接口,除非我找到了这样做的特定好处。

      最后,在A类具有对B类的具体引用的情况下,我没有看到对B类与接口类A无关的部分的更改将如何破坏A类。