如何解耦这种传递依赖
How to decouple this transitive dependency
我正在尝试找出如何从我的服务中删除传递依赖项。
让我们调用我的服务 ServiceA.
ServiceA 依赖于 LibraryB。 库 B 依赖于 库 C。因此 ServiceA 可传递地依赖于 LibraryC。让我解释一下如何...
在这种情况下,LibraryC 恰好是 ozzo-validation 库。在这个库中,有一个名为 Errors
的类型被定义为 map[string]error
。您可以在 https://github.com/go-ozzo/ozzo-validation/blob/v3.6.0/error.go 看到它,但这里仅供参考:
package validation
type Errors map[string]error
// Implement the error interface
func (es Errors) Error() string {
// Implementation omitted for brevity
}
注意类型 Errors
实现了 error
接口。
正如我已经写过的,LibraryB 依赖于 LibraryC,ozzo-validation。 LibraryB对ozzo-validation的使用是这样的:
package web
// Error responds to a request with an error object and the specified status
func Error(w http.ResponseWriter, err error, status int) {
// Implementation omitted for brevity
errors, ok := err.(validation.Errors)
if ok {
for key, err1 := range errors {
// Implementation omitted for brevity
}
// Implementation omitted for brevity
}
// Implementation omitted for brevity
}
这就是全部用法。 LibraryB 导入 ozzo-validation 以便 LibraryB 可以进行类型断言,errors, ok := err.(validation.Errors)
,然后在地图上范围,for key, err1 := range errors
.
我的服务 ServiceA 不知道 LibraryB 依赖于 ozzo-validation. ServiceA 也想使用 ozzo-validation,但需要使用较新的版本,因为较新的版本具有更多的功能和一些重要的错误修复。这个较新的版本是 v4.3.0。 ServiceA 调用 ozzo-library 中的一些方法 return 一个 validation.Errors
实例并将该实例传递给 LibraryB 的 web.Error
函数作为 err error
参数。
这就是乐趣的开始。因为 ServiceA 正在传递一个 v4.3.0 validation.Errors
实例并且 LibraryB 是针对 v3.6.0 validation.Errors
的类型断言即使 v3.6.0 和 v4.3.0 中的类型定义完全相同,类型断言也会失败。
我该如何解决这个问题?
我可以访问 LibraryB 的源代码并且我可以更改它。我可以轻松升级 LibraryB 以使用 ozzo-validation 的 v4.3.0,但这会使这种传递耦合永久化。我宁愿完全删除这种传递耦合。
我尝试将 LibraryB 中的类型断言更改为
errors, ok := err.(map[string]error)
因为最终实例就是这样,map[string]error
但是编译器不喜欢那样,因为 map[string]error
没有实现 error
接口。
有什么方法可以让我自己的对象实现 error
并且也可以调整范围,这样我就可以将 v4.3.0 `validation.Errors 包装在某种接口或其他东西中那会打破这种传递耦合?
我该怎么做才能打破这种紧密的传递耦合?
如果 LibraryB 的向后兼容性是一个问题,那么将 LibraryB 中的 ozzo-validation 升级到 v4 不是一个选项。因为如果有一个ServiceD使用LibraryC@v3和LibraryB,这样的升级会破坏ServiceD。
幸运的是,在 Go Modules 的帮助下,LibraryB 可以导入 v3 和 v4,并对这两个版本进行类型断言。
package web
import (
validationv3 "github.com/go-ozzo/ozzo-validation/v3"
validationv4 "github.com/go-ozzo/ozzo-validation/v4"
)
// Error responds to a request with an error object and the specified status
func Error(w http.ResponseWriter, err error, status int) {
// Implementation omitted for brevity
errorsv3, ok := err.(validationv3.Errors)
if ok {
for key, err1 := range errorsv3 {
// Implementation omitted for brevity
}
// Implementation omitted for brevity
}
// Implementation omitted for brevity
errorsv4, ok := err.(validationv4.Errors)
if ok {
for key, err1 := range errorsv4 {
// Implementation omitted for brevity
}
// Implementation omitted for brevity
}
// Implementation omitted for brevity
}
我正在尝试找出如何从我的服务中删除传递依赖项。
让我们调用我的服务 ServiceA.
ServiceA 依赖于 LibraryB。 库 B 依赖于 库 C。因此 ServiceA 可传递地依赖于 LibraryC。让我解释一下如何...
在这种情况下,LibraryC 恰好是 ozzo-validation 库。在这个库中,有一个名为 Errors
的类型被定义为 map[string]error
。您可以在 https://github.com/go-ozzo/ozzo-validation/blob/v3.6.0/error.go 看到它,但这里仅供参考:
package validation
type Errors map[string]error
// Implement the error interface
func (es Errors) Error() string {
// Implementation omitted for brevity
}
注意类型 Errors
实现了 error
接口。
正如我已经写过的,LibraryB 依赖于 LibraryC,ozzo-validation。 LibraryB对ozzo-validation的使用是这样的:
package web
// Error responds to a request with an error object and the specified status
func Error(w http.ResponseWriter, err error, status int) {
// Implementation omitted for brevity
errors, ok := err.(validation.Errors)
if ok {
for key, err1 := range errors {
// Implementation omitted for brevity
}
// Implementation omitted for brevity
}
// Implementation omitted for brevity
}
这就是全部用法。 LibraryB 导入 ozzo-validation 以便 LibraryB 可以进行类型断言,errors, ok := err.(validation.Errors)
,然后在地图上范围,for key, err1 := range errors
.
我的服务 ServiceA 不知道 LibraryB 依赖于 ozzo-validation. ServiceA 也想使用 ozzo-validation,但需要使用较新的版本,因为较新的版本具有更多的功能和一些重要的错误修复。这个较新的版本是 v4.3.0。 ServiceA 调用 ozzo-library 中的一些方法 return 一个 validation.Errors
实例并将该实例传递给 LibraryB 的 web.Error
函数作为 err error
参数。
这就是乐趣的开始。因为 ServiceA 正在传递一个 v4.3.0 validation.Errors
实例并且 LibraryB 是针对 v3.6.0 validation.Errors
的类型断言即使 v3.6.0 和 v4.3.0 中的类型定义完全相同,类型断言也会失败。
我该如何解决这个问题?
我可以访问 LibraryB 的源代码并且我可以更改它。我可以轻松升级 LibraryB 以使用 ozzo-validation 的 v4.3.0,但这会使这种传递耦合永久化。我宁愿完全删除这种传递耦合。
我尝试将 LibraryB 中的类型断言更改为
errors, ok := err.(map[string]error)
因为最终实例就是这样,map[string]error
但是编译器不喜欢那样,因为 map[string]error
没有实现 error
接口。
有什么方法可以让我自己的对象实现 error
并且也可以调整范围,这样我就可以将 v4.3.0 `validation.Errors 包装在某种接口或其他东西中那会打破这种传递耦合?
我该怎么做才能打破这种紧密的传递耦合?
如果 LibraryB 的向后兼容性是一个问题,那么将 LibraryB 中的 ozzo-validation 升级到 v4 不是一个选项。因为如果有一个ServiceD使用LibraryC@v3和LibraryB,这样的升级会破坏ServiceD。
幸运的是,在 Go Modules 的帮助下,LibraryB 可以导入 v3 和 v4,并对这两个版本进行类型断言。
package web
import (
validationv3 "github.com/go-ozzo/ozzo-validation/v3"
validationv4 "github.com/go-ozzo/ozzo-validation/v4"
)
// Error responds to a request with an error object and the specified status
func Error(w http.ResponseWriter, err error, status int) {
// Implementation omitted for brevity
errorsv3, ok := err.(validationv3.Errors)
if ok {
for key, err1 := range errorsv3 {
// Implementation omitted for brevity
}
// Implementation omitted for brevity
}
// Implementation omitted for brevity
errorsv4, ok := err.(validationv4.Errors)
if ok {
for key, err1 := range errorsv4 {
// Implementation omitted for brevity
}
// Implementation omitted for brevity
}
// Implementation omitted for brevity
}