我正在使用Djinni在android和ios之间分享一些大的c ++代码库。其中一个组件(让我们称之为Foo
!!!)在android和ios上有不同的实现。 FooAndroid
是一个接口,c ++代码使用它而不需要了解其内部结构。
虽然android实现(FooAndroid
),有一些额外的方法,Android客户端可以使用这些方法修改组件的行为,只对android平台有意义。
由于缺乏接口继承,这使djinni变得复杂。我提出了一种解决方案,它依赖于foo = interface +c {
static create() : foo;
doSomething();
}
foo_android = interface +c {
static create() : foo_android;
doSomething();
doAnotherThing();
asFoo(): foo;
}
bar = interface +c {
static create() : bar;
useFoo(f: foo);
}
可以继承两个不同djinni接口的事实,这些接口的大多数方法具有相同的签名,但结果并不漂亮。
这是djinni界面描述:
Bar
您会注意到Foo
只需要访问// Foo android implementation:
class FooAndroidImpl : public Foo, public FooAndroid {
public:
void doSomething() override { LOGI("do something"); }
void doAnotherThing() override { LOGI(" do something"); }
std::weak_ptr<Api::Foo> fooSelfReference;
std::shared_ptr<Api::Foo> asFoo() override { return fooSelfRef.lock(); }
};
// instance creation methods:
std::shared_ptr<FooAndroidImpl> createImpl() {
auto p = std::make_shared<FooAndroidImpl>();
p->fooSelfRef = p;
return p;
}
std::shared_ptr<FooAndroid> FooAndroid::create()
{
return createImpl();
}
std::shared_ptr<Foo> Foo::create()
{
return createImpl();
}
// Bar implementation:
class BarImpl : public Bar {
public:
void useFoo(const std::shared_ptr<Foo> & f) override { f->doSomething(); }
};
std::shared_ptr<Bar> Bar::create()
{
return std::make_shared<BarImpl>();
}
个实例的组件。
然后以这种方式实现生成的接口:
FooAndroid fooAndroid = FooAndroid.create();
fooAndroid.doAnotherThing();
Bar bar = Bar.create();
bar.useFoo(fooAndroid.asFoo());
然后我可以用这种方式在java中使用FooAndroid和Bar:
{{1}}
这很有效,但它很难看,我必须手动定义两个几乎相同的djinni接口,而且我还不确定将weak_ptr存储在对象生命周期中的所有含义。
我觉得我在滥用Djinni的目的和模式,所以也许有更好的方法来实现我想要做的事情?
答案 0 :(得分:2)
Djinni不支持界面继承,所以这里不是一个好的答案。在Dropbox,这并不常见,我们通常只需将Android / iOS特定方法添加到单个界面,并使用存根在其他平台上引发异常来实现它。但是,我们通常遇到相反的情况,实现是在Java / ObjC中。
如果您不喜欢这种方法,并且不喜欢方法重复和多重继承,我认为我推荐的另一种方法是使用相关的子对象。例如。有一个带有getAndroidStuff()方法的Foo接口,它返回一个只包含Android特定方法的FooAndroid接口。 FooAndroid对象可以在内部将引用保存回FooImpl对象,该对象具有所有功能,并向前转发方法。
这里似乎更广泛的问题是关于这些方法的特定平台?如果实现是跨平台的,但只需要在一个平台上,那么让一个C ++类代替它并不会有什么坏处,并且未使用的方法是非危险的。如果您在C ++中获得了特定于平台的代码,那么事情会有点尴尬,因为这不是Djinni的设计目标。我认为这个具体案例需要一个与接口继承的一般情况不同的解决方案。