API设计原则学习笔记

Qt图形界面库的设计在接口API设计中算是十分优秀的,前几天在coolShell上看到了一篇强烈推荐的API设计原则文章,仔细研究了下,文章地址如下:

 http://developer.qt.nokia.com/wiki/API_Design_Principles

简单记录了一下重点和难点,以备忘。

High point:

Static Polymorphism

Similar classes should have a similar API. This can be done using inheritance where it makes sense — that is, when run-time polymorphism is used. But polymorphism also happens at design time. For example, if you exchange a QProgressBar with a QSlider, or a QString with a QByteArray, you’ll find that the similarity of APIs makes this replacement very easy. This is what we call “static polymorphism”.

静态多态,相似的类之间他们的API也相似,这样就有了好的替换性。

Static polymorphism also makes it easier to memorize APIs and programming patterns.

这样带来的好处还有易于记忆和设计接口。

Property-Based APIs

这里所有的类中的属性应该尽量可供用户设置。需要强调的一点是,类实例的属性设置顺序应该是可以乱序的。属性之间的设置应尽量正交,相互之间不会产生影响。

Sometimes, it’s useful to be able to reset a property. Then there are two approaches:

  • pass a special value (such as QSize(), -1, or Qt::Alignment(0)) to mean “reset”
  • have an explicit resetFoo() or unsetFoo() function

属性的重置有两种方法,使用通用API设置默认值,或者显式调用重置接口。

 

Pointers vs. References

使用指针还是引用?

void getHsv(int *h, int *s, int *v) const

void getHsv(int &h, int &s, int &v) const

上面是两种可能的API。参数应该用什么形式?大多数书里建议第二种,引用。因为引用更安全,更方便。但在设计API时,需要考虑调用方式。如:

color.getHsv(&h, &s, &v);

color.getHsv(h, s, v);

虽然都是调用,第一种明确告诉你参数可以被修改,但是第二种你完全不知道参数是否会被修改。

 

Virtual Functions

如果对于某类A,没有任何类会继承于他,他的变量不需要protected,他的函数也就不需要设置为虚函数。

There are many other reasons to avoid excessive use of virtual functions:

  • you cannot add, move or remove virtual functions without breaking BC
  • you cannot easily overload a virtual function
  • compilers can almost never optimize or inline calls to virtual functions
  • calling the function requires a v-table lookup, making it 2-3 times slower than a normal function
  • virtual functions make the class hard to copy by value (possible, but very messy and discouraged)

Experience has taught us that a class with no virtual functions tends to have fewer bugs and generally causes less maintenance.

 

Input arguments: const pointers

Const functions that take input pointer arguments almost always take const pointer arguments.

类成员函数如果是const函数,通常该函数的输入参数也是const类型的。

Return values: const values

non-const R-value不会检查函数返回值是否为const,因此可以修改non-const R-value函数的返回的引用对象。_const_ R-value返回的引用的const对象是不可被修改的。

另外需要强调的是,lvalue和rvalue。

Lvalue的意思是存储地址属性,rvalue指的是readable value,可以读取的值属性。而不是什么左值右值。

Return values: pointers vs. const pointers

C++里一般建议如果函数是常量函数,则返回参数也使用常量,避免返回一个非常量变量使得类对象有被修改的风险。但是返回参数使用常量可能会导致很难使用的API,可能会需要const_cast。所以,权衡风险,有时返回非常量变量会有更大的好处。

 

General Naming Rules

l  尽量避免使用缩写。

l  设计类时,保证子类的命名空间干净。不要出现近似的词语,如name,caption这样的API名字人们很难分清。可以考虑使用更有意义的短语。

l  做好API的文档注释。如果一个函数或者变量没法用合适的词语精确描述,通常是这个条目不适合存在。如果你的确想描述他,就自己创造词语描述他,并解释清楚。

 

Naming Classes

Identify groups of classes instead of finding the perfect name for each individual class. 

One guideline for naming enum types is to repeat at least one element of the enum type name in each of the enum values.

 

Naming Functions and Parameters

The number one rule of function naming is that it should be clear from the name whether the function has side-effects or not. Parameter names are an important source of information to the programmer.

 

Naming Boolean Getters, Setters, and Properties

  • Adjectives are prefixed with is-. Examples:
    • isChecked()
    • isDown()
    • isEmpty()
    • isMovingEnabled()
  • However, adjectives applying to a plural noun have no prefix:
    • scrollBarsEnabled(), not areScrollBarsEnabled()
  • Verbs have no prefix and don’t use the third person (-s):
    • acceptDrops(), not acceptsDrops()
    • allColumnsShowFocus()
  • Nouns generally have no prefix:
    • autoCompletion(), not isAutoCompletion()
    • boundaryChecking()
  • Sometimes, having no prefix is misleading, in which case we prefix with is-:
    • isOpenGLAvailable(), not openGL()
    • isDialog(), not dialog() (From a function called dialog(), we would normally expect that it returns a QDialog **.)

 

Avoiding Common Traps

The Convenience Trap

It is a common misconception that the less code you need to achieve something, the better the API.

最好不要让函数参数过多,否则这样的API设计出来很难懂。

 

The Boolean Parameter Trap

An obvious solution is to replace the bool parameters with enum types.

用enum结构替换,或者设计多个API代替原来的一个。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值