我正在为现有的库编写FFI接口(用C语言编写)。
该库使用大量不透明结构,因此我定义了一些ExternalStructures
(没有字段)用作void*
。
现在我已经看到了与库连接的两种方式(或四种方式):
每个导出函数都有ExternalLibrary
方法:这可以在实例类中使用方法,然后使用单例模式来生成单个实例。或者使用“更复杂”的语法实现类侧的方法,包括FFI pragma中的moduleName
,如:
ffiTestFloats: f1 with: f2
"FFITestLibrary ffiTestFloats: $A with: 65.0"
<cdecl: float 'ffiTestFloats' (float float) module:'SqueakFFIPrims'>
^self externalCallFailed
什么更好?
此外,我已经看到了这样做的其他方式,根本没有ExternalLibrary
,并直接在ExternalStructure
中实现这些方法。我更喜欢第二部分,但是,所有FFI接口定义都通过几个类传播,维护和移植到其他平台,Smalltalk方言或库版本可能更复杂。
那么,做到这一点的“正确”方式是什么?
答案 0 :(得分:3)
我会使用ExternalLibrary
方法,因为它允许您自定义库名称,而不是在每种方法中对其进行硬编码。
答案 1 :(得分:1)
我更喜欢第一个选项,一个表示外部库的对象,在C函数和实例方法之间有一对一的映射。当然,这是较低级别的抽象,因此应该构建更好的抽象。 我不会使用“单身人士”,我认为不需要“班级的一个实例”。你需要的是一个众所周知的对象,并且不应该直接从内部引用该对象以避免耦合,它应该在需要时作为参数传递。
答案 2 :(得分:1)
我会坚持使用传统的方法对事物进行建模。我们这里有一个外部库,然后让我们为它创建一个类,并在我们的对象中复制它的API,当然,使用执行所需FFI调用的实例端方法。
我们已经使用这种方法已有二十年了,而且经验表明单例模式在这种情况下非常有效,因为它使客户的生活变得轻松。当然,这个工具必须小心处理,因此您不能从不适当的地方引用库实例。但请注意,这不是一个必要的决定,但您必须以某种方式将库的唯一实例存储在某处。
在所涉及的外部结构中实现FFI调用并不自然,因为某些调用可能涉及多个结构或根本不存在任何结构。那么,你会把它们放在哪里?
您还提到了在类侧实现方法的想法。毕竟,我们都同意,每个图书馆应该只有一个实例,不应该吗?放弃这种可能性的一个原因是类侧方法将提供不太灵活的实现。为什么?因为有一件事是使用某种机制只有一个类的实例而另一个是让它不可能拥有它。如果您的对象是一个实例(而不是一个类),您仍然可以避免明确鼓励限制单个实例并能够创建另一个实例。这会违反您自己的规则,但最好能够这样做。想要这样做的一个简单案例是测试。您可以创建第二个连接到另一个版本的库的实例,并在不必修改类的情况下对其进行测试。不选择类方法的另一个原因是更微妙:类代表事物的概念,而不是事物的概念。因此,它们的自然协议与其实例的协议不同。将两个接口分开将增加设计的清晰度。