让接口更容易被正确的使用,而且不容易被错误的使用

ps:转载于公司大佬,版权@copyright horizon.ai

Choose good names

class AbcInterface {
 public:
  bool CreateFilter() { return false; } 
};

Create一般用于对象的创建,但是返回值是个bool,Create一个Bool?


class XyzModule {
 public:
  bool& GetEnable() { return is_enable_; } 
 private:
  bool is_enable_;
};

Get一般用于获取一个值,不改变一个值, 容易造成误导


class XyzModule : public ADASModule {
 public:
  FORWARD_DECLARE(XyzModule , 0);
  FORWARD_DECLARE(XyzModule , 1);
  FORWARD_DECLARE(XyzModule , 2);
  FORWARD_DECLARE(XyzModule , 3);
  FORWARD_DECLARE(XyzModule , 4);
  FORWARD_DECLARE(XyzModule , 5);
  FORWARD_DECLARE(XyzModule , 6);
  ...
};

这样看上去,可以得到的有效信息很少,只能从cpp实现中推测函数的功能


Incapsulate

不暴露指针

class TraceObject{
 public:
  bool Predict(Mat);
  TraceObject* related_object_;
};

直接暴露空指针会导致使用者存在很多错误的使用情况

  • 有两个线程使用同时操作related_object_
  • 指针可能被外部的用户存储,但是这个TraceObject已经被delete了

使用progressive disclosure

class TrackingObject{
 public:
  virtual int PredictOneFrame(Observation);
  int &GetMissDetection();
  int &GetMissTracking();
  void SetMissDetection(int value);
  int GetContinueDetction();
  void AddContinueDetction();
  void ResetContinueDetction();
  // 50 more ...
};

过多的public函数,使用者会无从下手,阅读者很难理解这个类的用途

class TrackingObject{
 public:
  struct AdvancedFeature {
    int &GetMissDetection();
    int &GetMissTracking();
    void SetMissDetection(int value);
    int GetContinueDetction();
    void AddContinueDetction();
    void ResetContinueDetction();
    ...
  }
  virtual int PredictOneFrame(Observation);
  AdvancedFeature& Advanced();
  ...
};

// example
obj.PredictOneFrame(observation);
obj.Advanced().SetMissDetection(1);

引入新类型来杜绝错误的使用

void *BPUMemAlloc(
    int32_t core_id, uint32_t byte_size, bool cacheable,
    int32_t type = BPUMemOutput, int32_t cam_id = 0);

在参数比较多的情况下,使用者容易发生传入参数顺序错误的情况

enum class MemType : uint32_t {
  BPUMemOutput
};
void *BPUMemAlloc(
    int32_t core_id, uint32_t byte_size, bool cacheable,
    MemType type = MemType::BPUMemOutput, int32_t cam_id = 0);

尽可能的使用explict type来enable编译器的检查

virtual dispatcher alternatives

virtual的实现一般采用virtual table, vtable存在一定的cost,每个对象的会至少多存储一个vtable_ptr, 多重继承会更多,而且会增加一张virtual table,同时也有runtime cost

virtual solution:

class FilterBase {
  virtual bool Filter() = 0;
}

class AbcFilter {
  virtual bool Filter() override {
    ...
  }
}

possible solution without virtual:

template <typename FilterImpl>
class FilterBase {
  bool Filter() {
    return static_cast<FilterImpl>(*this).Filter();
  }
}
class AbcFilter : public FilterBase<AbcFilter> {
  bool Filter() { ... }
}

Pros:No vtable overhead, Cons:代码看起来没有virtual简单

好习惯

写接口前先画UML,写接口文档

// Set image frame info to Frame handle.
// @param[in] frame A handle of Frame.
// @param[in] width The width of Frame.
// @param[in] height The height of Frame.
// @param[in] count The count height of Frame.
// @note All frames are based on frame, so  width and height,
// count is required.
ABC_SDK
void SetFrameInfo(Frame frame, int32_t width, int32_t height,
                       int count);

Q.E.D.


ALL WILL BE CLEAR