当我想告诉中间包关于这些其他软件包时,这一切分崩离析,所以它知道它可以创建什么客户端.这些依赖客户端实现也导入中央包,创建Go不允许的循环依赖.
最好的方法是什么?我不想在一个包中将所有这些实现进行混合,并且创建一个单独的注册表包看起来是过度的.目前,我有每个实现注册本身与中央包,但是这需要用户知道导入使用客户端的每个单独的二进制文件中的每个实现.
import ( _ udpclient _ tcpclient client )
1)没有“中央”登记处
这个例子就是不同的散列算法. crypto
软件包只是定义了Hash
接口(类型及其方法).具体的实现方式是不同的包(实际上是子文件夹,但不需要),例如crypto/md5
和crypto/sha256
.
当你需要一个“哈希尔”时,你明确地说出你想要的那个,并实例化一个.
h1 := md5.New() h2 := sha256.New()
这是最简单的解决方案,它也提供了良好的分离:哈希包不必知道或担心实现.
如果您知道或者您可以决定先前需要哪个实现,这是首选解决方案.
2)与“中央”登记处
这基本上是你提出的解决方案.实现必须以某种方式注册(通常是在一个包init()函数中).
一个例子是image
包.该软件包定义了Image
接口及其几个实现.不同的图像格式在不同的包中定义,如image/gif
,image/jpeg
和image/png
.
该图像包具有Decode()
功能,它从指定的io.Reader
解码并返回Image
.通常,未知哪个类型的图像来自于读取器,因此您不能使用特定图像格式的解码器算法.
在这种情况下,如果我们想要图像解码机制是可扩展的,则注册是不可避免的.最简单的做法是在包init()函数中,通过在导入时指定包名称的空白标识符来触发.
请注意,此解决方案还提供了使用特定实现来解码图像的可能性,具体实现还提供了Decode()函数,例如png.Decode()
.
那么最好的方法?
取决于您的要求.如果你知道或者你可以决定你需要哪个实现,那么你可以去#1.如果您无法决定或不知道您需要可扩展性,请与#2进行交流.
…或下面提到#3.
您仍然可以方便地使用“中央”注册表,其界面和实现与“自动扩展性”的费用分开.
这个想法是,你有包pi的接口.你有包pa,pb等的实现
并且您创建一个将要使用“工厂”方法的包pf,例如pf.NewClient(). pf包可以引用包pa,pb,pi,而不创建循环依赖.