1 回答
TA贡献1831条经验 获得超10个赞
标准库通过多种方式解决了这个问题:
1) 没有“中央”注册表
这方面的例子是不同的哈希算法。该crypto包仅定义了Hash接口(类型及其方法)。具体的实现在不同的包中(实际上是子文件夹,但不需要),例如crypto/md5和crypto/sha256。
当你需要一个“散列器”时,你明确说明你想要哪个并实例化那个,例如
h1 := md5.New()
h2 := sha256.New()
这是最简单的解决方案,它还为您提供了良好的分离:hash包不必知道或担心实现。
如果您知道或者您可以决定您想要的实现方式,那么这是首选的解决方案。
2) 使用“中央”注册表
这基本上是您提出的解决方案。实现必须以某种方式(通常在包init()函数中)注册自己。
这方面的一个例子是image包。该包定义了Image接口及其几个实现。在不同的包中定义了不同的图像格式,例如image/gif、image/jpeg和image/png。
该image包有一个Decode()函数,它Image从指定的io.Reader. 通常不知道来自阅读器的图像类型是什么,因此您不能使用特定图像格式的解码器算法。
在这种情况下,如果我们希望图像解码机制是可扩展的,注册是不可避免的。最干净的方法是在包init()函数中,它是通过在导入时为包名指定空白标识符来触发的。
请注意,此解决方案还为您提供了使用特定实现来解码图像的可能性,具体实现也提供了该Decode()功能,例如png.Decode().
那么最好的方法是什么?
取决于你的要求是什么。如果您知道或可以决定您需要哪种实现,请选择 #1。如果您无法决定或不知道并且需要可扩展性,请选择#2。
...或者使用下面介绍的#3。
3)提出第三个解决方案:“自定义”注册表
您仍然可以享受“中央”注册表的便利,将接口和实现分开,但要付出“自动扩展性”的代价。
这个想法是你在 package 中有接口pi。你必须在包的实现pa,pb等等。
并且您创建了一个包含pf您想要的“工厂”方法的包,例如pf.NewClient(). 该pf包可以指包pa,pb,pi而不创建循环依赖关系。
- 1 回答
- 0 关注
- 158 浏览
添加回答
举报