3 回答
TA贡献1825条经验 获得超6个赞
我会说这归结为你能控制什么。在您的示例中,您似乎描述了两个单独的包。有多种方法可以处理此问题:
接受一个函数
您可以修改ApiFunction以接受处理您想要的情况的功能:
type consumerDeps interface {
ApiFunction(func() string) string
}
这将允许您将您想要的确切功能注入消费者。然而,这里的缺点是这会很快变得混乱,并且会混淆定义函数的意图,并在实现接口时导致意想不到的后果。
接受接口{}
您可以修改ApiFunction以接受interface{}由实现接口的人处理的对象:
type consumerDeps interface {
ApiFunction(interface{}) string
}
type producer struct{}
type apiFunctionInput interface {
hello() string
}
func (producer) ApiFunction(i interface{}) string {
return i.(apiFunctionInput).hello()
}
这稍微好一点,但现在您依赖于生产者端正确解释数据,如果它没有执行此操作所需的所有上下文,那么如果它转换为,您可能会出现意外行为或恐慌错误的类型。
接受第三方接口
您还可以创建一个第三方接口,在这里称之为适配器,它将定义生产者端和消费者端都可以同意的功能:
type Adapter interface {
hello() string
}
type consumerDeps interface {
ApiFunction(Adapter) string
}
现在,您有一个数据合同,可用于由消费者发送和由生产者接收。这可能像定义一个单独的包一样简单,也可能像整个存储库一样复杂。
重新设计
最后,你可以重新设计你的代码库,这样生产者和消费者就不会像这样耦合在一起。虽然我不知道您的具体用例,但您遇到这个特定问题这一事实意味着您的代码耦合得太紧,可能应该重新设计。消费者端和生产者端包之间可能有一个元素拆分,可以提取到第三个包。
TA贡献1725条经验 获得超7个赞
我不太清楚你为什么要介绍这个myRequirements界面。如果Chef需要一个FruittoCut并且你想定义一个特定的水果Apple- 你需要做的就是定义一个Apple实现接口的结构Fruit。
type Chef struct {
}
type fruit interface {
Cut() error
}
func (c Chef) Cut(fruit fruit) error {
return fruit.Cut()
}
然后,您需要做的就是根据您的要求定义Apple实现接口的对象:Fruit
package kitchen
import chef "goplayground/interfaces/fruits/chef"
type Apple struct {
}
func (a Apple) Cut() error {
// lets cut
return nil
}
type myRequirements interface {
Cut(Apple) error
}
type myChef struct {
chef chef.Chef
}
func (m myChef) Cut(apple Apple) error {
// since Apple implements the chef`s fruit interface this is possible
return m.chef.Cut(apple)
}
func cook() {
remy := myChef{}
apple := Apple{}
_ = remy.Cut(apple)
}
TA贡献1783条经验 获得超4个赞
正确使用 duck-typing 有一些细微差别,这就是 Go 类型系统在接口方面的作用。在使用它们的地方定义接口通常是一个好习惯,但io.Reader接口是在标准库中定义的。因此,该建议的适用性有限。
在你的例子中,包chef有两个接口,Chef和Fruit. 这两个接口紧密耦合,因为Chef有一个方法使用Fruit. 使用当前的 Go 类型系统,Chef如果不从该包中导出就无法使用Fruit。所以:
type myRequirements interface {
Cut(chef.Fruit) error
}
是您可以使用包中的实现的chef.Chef唯一方法。Apple
但是你想要做的是:
type myRequirements interface {
Cut(Apple) error
}
并且您希望能够传达这是 的子集Chef,也就是说, 的语义Cut与 的语义相同Chef。好吧,语义是不同的。否则是不安全的。
说,你实施Apple为:
type Apple struct {}
func (a Apple) SomeFunc()
func (a Apple) FruitFunc()
而是chef.Fruit:
type Fruit interface {
FruitFunc()
}
显然,Appleimplements chef.Fruit,因此您可以传递到需要Applea 的任何地方。chef.Fruit但是你不能传递chef.Fruit给myRequirements.Cut(Apple)函数。因为 in myRequirements.Cutyou 也暗示你可以使用Apple.SomeFunc, which is not defined in chef.Fruit.
所以,如果你真的想定义一个像 的接口myRequirements,那么你必须使用chef.Fruit. 如果你定义的是using Apple,那么myRequirements.Cut方法就不同于chef.Cut。
- 3 回答
- 0 关注
- 140 浏览
添加回答
举报