mercredi 22 juin 2022

How to provide an opaque public handle in public API while still able to touch the implementation detail inside internal component?

I am refactoring a biometric recognition SDK, which public API provide feature extraction and some CRUD feature management interface like:

class PublicComponent{
public:
  FeaturePublic extract_feature();
  int add_feature(const FeaturePublic&);
  void update_feature(int id, const FeaturePublic&);
  void delete_feature(int id);
}

The actual feature that all other private implementation component must to deal with is complicated, it contains many fields that we don't want to expose to the API user, like:

struct FeatureDetail{
  int detail1;
  int detail2;
  // ...
  float detailN;
};

And basically the PublicComponent just forward its job to these internal components.

So the gap occurred, basically all the public API accept or give back FeaturePublic as argument/result. However all other existed internal implementation heavily depends on FeatureDetail, they must touch the internal data member of feature. It just seems that we need to retrieve concrete type from the type erased public handle, but unable to publish the retrieve method. I've came up with two solutions, but either of them seems quirky.

Solution 1

Just use type erased raw buffer like std::vector<std::byte> or std::pair<std::byte*, size_t> as FeaturePublic.

It is simple, however, the cons is pretty straightforward: We just throw away the type safety that we already have, and i have to insert all the input data integrity check and serialize/deserialize code at all the public API border even though the caller might just add a feature that generated right before.

Solution 2

Use pimpl like idiom to hide FeatureDetail inside FeaturePublic.

// public api header
class FeatureDetail; // forward declartion

class FeaturePublic{
private:
  std::unique_ptr<FeatureDetail> detail_;
};

Under which we can maintain the type safety, however, to let the internal component to touch the concrete type FeatureDetail, we must have some way to let them retrieve a FeatureDetail from PublicComponent passed FeaturePublic. But since the detail_ field is a private member, The two ways that i can think of is to provide a get_raw method on FeaturePublic or make the field public, any of them seems pretty ugly.

Aucun commentaire:

Enregistrer un commentaire