如何设计优雅、简洁、强壮的库?


在学堂在线,看见了清华大学乔林教授讲的一门课《基于Linux 的C++》,讲得非常棒,特地记录了部分笔记。

笔记来源课程:

学堂在线 清华大学 20740084X 基于Linux的C++(2016春)

接口

通过接口使用库:包括制定库的头文件与源文件。
优势:不需要了解库的实现细节,只需了解库的使用方法。

接口设计的一般原则:

用途一致

 接口中所有函数都属于同一类问题

操作简单

 函数调用方便,最大限度隐藏操作细节

功能充足

 满足不同潜在用户的需要

性能稳定

 经过严格测试,不存在程序缺陷

下面以实现随机库为例,说明库的设计与实现。

随机库要实现的功能:

1. 在指定范围内随机生成整数。
2. 在制定范围内随机生成浮点数。

设计随机库的接口:

//随机化函数
void Randomize();

//指定范围内随机生成整数
int GenerateRandomNumber( int low, int high );
在制定范围内随机生成浮点数。
double GenerateRandomReal( double low, double high );

实现随机数库:

void Randomize()
{
    srand((int)time(NULL));
}

int GenerateRandomNumber(int low,int high)
{
    double _d;
    if(low>high) //容错设置
    {
        cout <<"GenerateRandomNumber:Make sure low<=high.\n";
        exit(1);
    }
    //做映射,加1.0是为了让_d落在[0,1)区间,这样_d * (high - low +1)强制转换为int后最大为high - low,结果不会超过high
    _d = (double)rand() / ((double)RAND_MAX + 1.0); 
    return( low + (int)(_d * (high - low +1) ) );
}

double GenerateRandomReal(double low,double high)
{
    double _d;
    if(low>high) 
    {
         cout << "GenerateRandomReal:Make sure low <= high.\n";
         exit(2);
    }
    _d = (double)rand() / (double)RAND_MAX;
    return( low + _d * (high -low) );
}

最终程序

我们需要创建3个文件,分别为

//头文件:random.h

void Randomize();

int GenerateRandomNumber(int low,int high);

double GenerateRandomReal(double low,double high);

源文件: random.cpp

#include<iostream>
#include<cstdlib>
#include"random.h"
#include<ctime>

using namespace std;

:void Randomize()
{
    srand((int)time(NULL));
}

int GenerateRandomNumber(int low,int high)
{
    double _d;
    if(low>high)
    {
    //做映射,加1.0是为了让_d落在[0,1)区间,这样_d * (high - low +1)强制转换为int后最大为high - low,结果不会超过high
        cout <<"GenerateRandomNumber:Make sure low<=high.\n";
        exit(1);
    }
    _d = (double)rand() / ((double)RAND_MAX + 1.0);
    return( low + (int)(_d * (high - low +1) ) );
}

double GenerateRandomReal(double low,double high)
{
    double _d;
    if(low>high)
    {
         cout << "GenerateRandomReal:Make sure low <= high.\n";
         exit(2);
    }
    _d = (double)rand() / (double)RAND_MAX;
    return( low + _d * (high -low) );
}

测试文件:main.cpp

#include<iostream>
#include"random.h"
using namespace std;

int main()
{
    int i;
    Randomize();
    for( i=0;i<8;i++) // 产生8个指定范围内的随机整数
    {
        int t = GenerateRandomNumber(10,90);
        cout << t <<";";
    }
    cout << endl;
    for(i =0; i<8;i++) // 产生8个指定范围内的随机浮点数
    {
        double t = GenerateRandomReal(10.0,90.0);
        cout << t <<";";
    }
    cout << endl;

return 0;


}

随机数库的测试

linux 环境下使用g++编译器执行下列命令编译链接生成a.out

g++ main.cpp random.cpp

运行a.out

./a.out

----------------------------------------------------
或者先执行
g++ -o random main.cpp random.cpp

再运行
c++
./random

单独测试库的所有函数

合法参数时返回结果是否正确
非法参数返回结果是否正确,即容错功能是否正常

非法参数返回正确:

联合测试

 多次运行程序,查看生成的数据是否随机
 测试整数和浮点数随机数是否均能正常工作

测试正确:

改进

Randomize();这条语句放在main()里面是不太好的,用户可能会忘记写了而造成错误,因此一个更好的方法是在GenerateRandomNumber(),和GenerateRandomReal()函数第一次被调用时自动调用它(用一个静态变量记录是否已经播种,保证srand只调用一次;如果每次都调用srand((int)time(NULL)),同一秒内得到的随机数都一样),这样就防止了用户万一没有添加Randomize()而出错,而且对用户来说也是屏蔽了细节,现在用户只需知道GenerateRandomNumber(),和GenerateRandomReal()函数怎么用就行了。

请我喝杯咖啡