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:
属性的重置有两种方法,使用通用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:
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
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代替原来的一个。