2

我正在使用 Djinni 在 android 和 ios 之间共享一些大型 c++ 代码库。各种组件之一(我们称之为Foo!!!)在 android 和 ios 上具有不同的实现。Foo是一个接口,c++ 代码无需了解其内部结构就可以使用该接口。

android 实现虽然 ( FooAndroid) 有一些额外的方法,android 客户端可以使用这些方法以仅对 android 平台有意义的方式修改组件的行为。

由于缺乏接口继承,这使 djinni 的事情变得复杂。我想出了一种解决方案,它依赖于这样一个事实,即FooAndroid可以子类化两个不同的 djinni 接口,它们的大多数方法都具有相同的签名,但结果并不漂亮。

这是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);
}

您会注意到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>();
}

然后我可以通过这种方式在 java 中使用 FooAndroid 和 Bar:

FooAndroid fooAndroid = FooAndroid.create();
fooAndroid.doAnotherThing();
Bar bar = Bar.create();
bar.useFoo(fooAndroid.asFoo());

这行得通,但很难看,我必须手动定义两个几乎相同的 djinni 接口,而且我仍然不确定存储该 weak_ptr 对对象生命周期的所有影响。

我觉得我在滥用 Djinni 的目的和模式,所以也许有更好的方法来实现我想要做的事情?

4

1 回答 1

3

Djinni 不支持接口继承,所以这里没有很好的答案。在 Dropbox,这并不经常出现,我们通常通过将 Android/iOS 特定方法添加到单个接口,并使用在其他平台上引发异常的存根来实现它们来解决它。不过,我们通常会遇到相反的情况,即在 Java/ObjC 中实现。

如果您不喜欢这种方法,并且不喜欢方法重复和多重继承,我认为我推荐的另一种方法是使用相关的子对象。例如,有一个带有 getAndroidStuff() 方法的 Foo 接口,它返回一个仅包含 Android 特定方法的 FooAndroid 接口。FooAndroid 对象可以在内部保存对具有所有功能的 FooImpl 对象的引用,并将方法转发给它。

似乎这里更广泛的问题是这些方法真正特定于平台的是什么?如果实现是跨平台的,但只需要在一个平台上,那么只让一个 C++ 类站在其中并没有什么坏处,并且未使用的方法是无危险的。如果你在 C++ 中有特定于平台的代码,那么事情会变得有点尴尬,因为这不是 Djinni 的设计目标。不过,我认为这种特定情况需要一个不同于接口继承的一般情况的解决方案。

于 2018-05-10T03:50:21.350 回答