Interface 耦合:使用基本类型、接口或具体对象作为参数?

Interface 耦合:使用基本类型、接口或具体对象作为参数?,interface,dependencies,coupling,oop,Interface,Dependencies,Coupling,Oop,首先让我说,我对OO模式、实践、干净的代码等方面没有太多经验。 我正在学习所有这些技巧 最松散耦合的方式是使用原语类型来构造新对象或执行方法,但我认为这是不可行的,对吗? 因为它更容易出错。我可以放弃表示根本不存在的ID的整数。如果我要使用一个对象,我实际上知道它有有效的数据,否则该对象将不会被创建,或者将处于无效状态,我必须进行检查 说用具体的对象来实现这一点是邪恶的,我想我应该交出他们的接口,你们都知道。 更改具体类型而不是接口将导致依赖类型崩溃。在所有情况下都是这样吗?对于封闭的单个项目环

首先让我说,我对OO模式、实践、干净的代码等方面没有太多经验。 我正在学习所有这些技巧

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

说用具体的对象来实现这一点是邪恶的,我想我应该交出他们的接口,你们都知道。 更改具体类型而不是接口将导致依赖类型崩溃。在所有情况下都是这样吗?对于封闭的单个项目环境也是这样吗?
我只会理解,如果接口一经编写就不可触及,并且永远不会被修改/重构。

您应该在需要时使用所有东西。仅在有意义的情况下使用基本体。与混凝土类型相同。的确,最好是“耦合”到一个抽象,但是在许多情况下,您没有抽象,也不需要抽象。您可以从正在使用的所有对象中提取接口,但如果您没有真正的理由这样做,那么它将毫无意义

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

您可能希望提取接口的另一个原因是测试。当然,只有当具体类型用作依赖项并且其行为足够复杂时,才提取接口。如果依赖关系只是一个简单的数据到数据传输对象,则不需要对其进行抽象


这些东西大多来自经验,但经验法则是从具体类型开始,然后根据需要进行抽象。如果一个对象已经实现了一个包含您想要的功能的接口,请直接使用该接口。

您应该在需要时使用所有内容。仅在有意义的情况下使用基本体。与混凝土类型相同。的确,最好是“耦合”到一个抽象,但是在许多情况下,您没有抽象,也不需要抽象。您可以从正在使用的所有对象中提取接口,但如果您没有真正的理由这样做,那么它将毫无意义

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

您可能希望提取接口的另一个原因是测试。当然,只有当具体类型用作依赖项并且其行为足够复杂时,才提取接口。如果依赖关系只是一个简单的数据到数据传输对象,则不需要对其进行抽象


这些东西大多来自经验,但经验法则是从具体类型开始,然后根据需要进行抽象。如果一个对象已经实现了一个包含您想要的功能的接口,那么直接使用该接口。

我想这个问题会引起很多问题。我会尽量让事情尽量简短:

我可以放弃表示ID的整数,它们只做 不存在

从我的观点来看,程序是代表你的问题领域的计算模型。物理学家或天文学家可以通过编写方程来模拟一种现象。当您使用对象建模时,您所做的是使用某些特定规则创建该域的表示。所以,回到你的问题,你可以用一个整数来表示概念上的ID,但是在你的问题域中,你会有一个没有正确表示的概念,因为,例如,有些整数不是有效的ID。此外,除了概念上的问题外,问题在于不能添加新行为并将其委托给整数,如果可以的话,例如在Smalltalk ev中 任何东西都是一个对象,你可以扩展任何类。从建模的角度来看,这也是错误的。作为一个一般的经验法则,我认为一个模型缺乏抽象,当我必须写一个行为,在一个对象不应该有一个给定的责任。在本例中,类似于拥有一个带有类方法isValidId的Util类

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

100%同意。我写了一篇关于这一点的文章,你们可能会发现有用的免责声明:我在Quanbit研究公司工作

这篇文章说,用具体的东西来做这件事是邪恶的,, 相反,我应该交出他们的接口,你们都知道,我 猜测对具体类型(而不是接口)的更改将导致 要细分的依赖类型。在所有情况下都是这样吗

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

对于封闭的单个项目环境也是这样吗?我会的 只有当接口一经编写就不可接触时,才能理解这一点 永远不要再被修改/重构

在这一点上我不能同意。一个程序,作为一个计算模型,反映了我们在问题域的某个给定时间点所知道的。因此,我们对它的研究越多,我们对它的了解就越多。编程包括学习,当我们学习时,我们会更好地理解事物;因此,我们的模式发生了变化。随着模型的变化,我们用来表示它们的元素也会像类或接口一样发生变化。随着时间的推移,你会看到你的模型变得更加健壮,概念上的变化会减慢,在某个时候你会有一个稳定的模型。但变化是不可能的,而变化是你应该预料到的


HTH

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

我可以放弃表示ID的整数,它们只做 不存在

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

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

100%同意。我写了一篇关于这一点的文章,你们可能会发现有用的免责声明:我在Quanbit研究公司工作

这篇文章说,用具体的东西来做这件事是邪恶的,, 相反,我应该交出他们的接口,你们都知道,我 猜测对具体类型(而不是接口)的更改将导致 要细分的依赖类型。在所有情况下都是这样吗

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

对于封闭的单个项目环境也是这样吗?我会的 只有当接口一经编写就不可接触时,才能理解这一点 永远不要再被修改/重构

在这一点上我不能同意。一个程序,作为一个计算模型,反映了我们在问题域的某个给定时间点所知道的。因此,我们对它的研究越多,我们对它的了解就越多。编程包括学习,当我们学习时,我们会更好地理解事物;因此,我们的模式发生了变化。随着模型的变化,我们用来表示它们的元素也会像类或接口一样发生变化。随着时间的推移,你会看到你的模型变得更加健壮,概念上的变化会减慢,在某个时候你会有一个稳定的模型。但变化是不可能的,而变化是你应该预料到的


HTH

我认为答案通常是“视情况而定”。决策受以下因素影响:

您正在处理哪些类型的对象?域对象表示业务域或服务中的概念,例如提供查找或保存操作

您的应用程序有多大/复杂

您是否“拥有”所有正在使用的对象?您正在使用的对象是否有可能被您无法控制的其他人更改

在足够复杂的项目上,我喜欢使用以下设置:

包含获取ID并返回域对象的“查找器”服务对象和获取域对象的“保存”服务对象的

一种域模型,其中包含的域对象在其方法中只接受其他域对象

它获取ID,使用数据访问层检索域对象,在域模型中触发域操作,然后使用数据访问层保存更改

使用服务层的一个或多个UI层,提供ID

我将服务对象放在接口后面的数据访问层和服务层中,因为我希望能够在单元测试中轻松模拟这些组件。我通常不会为我的域对象创建接口,除非我发现这样做有特殊的好处


最后,如果类A具体引用了类B,我不认为对类B中与类A使用的接口无关的部分进行更改会破坏类A。

我认为答案通常是“视情况而定”。决策受以下因素影响:

您正在处理哪些类型的对象?域对象表示业务域或服务中的概念,例如提供查找或保存操作

您的应用程序有多大/复杂

您是否“拥有”所有正在使用的对象?您正在使用的对象是否有可能被您无法控制的其他人更改

在足够复杂的项目上,我喜欢使用以下设置:

包含获取ID并返回域对象的“查找器”服务对象和获取域对象的“保存”服务对象的

一种域模型,其中包含的域对象在其方法中只接受其他域对象

它获取ID,使用数据访问层检索域对象,在域模型中触发域操作,然后使用数据访问层保存更改

使用服务层的一个或多个UI层,提供ID

我将服务对象放在接口后面的数据访问层和服务层中,因为我希望能够在单元测试中轻松模拟这些组件。我通常不会为我的域对象创建接口,除非我发现这样做有特殊的好处

最后,在类A有一个对类B的具体引用的地方,我不认为对类B中与类A将使用的接口无关的部分的更改会破坏类A