【复读EffectiveC++18】条款18:让接口容易被正确使用,不容易被误用

条款18:让接口容易被正确使用,不容易被误用

开发者要注意,你的功能要尽全力去减少不确定性

一、有什么问题

取原书的例子:
存在一个日期类,他的本意是用来记录年月日的,因此构造函数就有着年月日三个入参;

class Date
{
public:
    Date(int month, int day, int year);
    // ...
};

现在考虑创建这个日期类的,这里会出现一个问题:

Date d(30, 3, 1995);    // 不存在30天
Date d(2, 30, 1995);   // 2月没有30天

这类错误数据其实很常见,它的成因,有可能是入参看错,有可能是不知 “ 常识 ” ,但归根结底就是,使用限制不明确。
我们无法强求用户,只能尽力限制住,用户什么不可以。

二、怎么解决

1、方法一

最笨的方法可以是:

Date::Date(int month, int day, int year)
{
	if(month == 2 && day >= 30)
		return;
	
	处理代码
	
}

在函数内部,具体的处理代码之前进行判断,如果出现不想要的情况就提前返回;
但,这种方法,只是治标不治本,穷举全部不想要情况,还是尽量作为一种辅助手段。

2、方法二

enum eMonth
{
	eMonth_Jan,
	eMonth_Feb,
	...
};

class Date
{
public:
    Date(eMonth month, int day, int year);
    // ...
};

Date d(eMonth_Jan, 30, 1995); 

使用枚举类型就进行限制,就可以很好的限制住像月份这样明确且有限的数据输入,保证使用者,不会给你写进去一个第30月进去,但也要考虑,日怎么写,用枚举?那要是输入限制在1-10000内的日也用枚举,那就不用干别的了。

3、方法三

许多客户端错误可以通过导入新类型预防。我们可以导入简单的外覆类型(wrapper type)来区别天数、月份、年份,然后于Date构造函数中使用这些类型:

class Month
{
public:
    static Month Jan()    // 函数,返回有效月份,稍后解释为什么使用函数而非对象
    {
        return Month(1);
    }
    
    static Month Feb()
    {
        return Month(2);
    }
    // ...
    static Montn Dec()
    {
        return Month(12);
    }
    // ...    其他成员函数

private:
    explicit Month(int m);    // 阻止生成其他月份,这是private的
    // ...
};

class Date
{
public:
    Date(Month month, int day, int year);
    // ...
};

Date d(Month::Jan(), 30, 1995); 

如此设计,也可以达到相同的防御效果。

三、拓展问题

Investment *createInvestment();

当有这样一个返回值为一个指针的接口,我们在使用的时候,就要注意别忘了用完就释放,但总会有人忘记释放;
因此,我们作为设计者,这种释放问题也是要防御的点,也是要限制住的。

要怎么做呢?

std::tr1::shared_ptr<Investment> createInvestment();

强迫用户使用智能指针不失为一种好选择。

四、总结

1、好的接口很容易被正确使用,不容易被误用。你应该在你的所有接口中努力达成这些性质。
2、促进正确使用的方法包括接口的一致性,以及与内置类型的行为兼容。
3、阻止误用的方法包括建立新类型,限制类型上的操作,束缚类型值,以及消除客户的资源管理责任。
4、trl::shared_ptr 支持定制型删除器(custom deleter)。这可防范 DLL 问题,可被用来自动解除互斥锁(mutexes,见条款14)等等。

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-18 08:44:01       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-18 08:44:01       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-18 08:44:01       57 阅读
  4. Python语言-面向对象

    2024-07-18 08:44:01       68 阅读

热门阅读

  1. vue3中的watch函数

    2024-07-18 08:44:01       22 阅读
  2. 力扣题解(目标和)

    2024-07-18 08:44:01       22 阅读
  3. oracle数据字典详解

    2024-07-18 08:44:01       17 阅读
  4. 自定义异常

    2024-07-18 08:44:01       20 阅读
  5. leetcode-46. 全排列

    2024-07-18 08:44:01       23 阅读
  6. 观察者模式-C#

    2024-07-18 08:44:01       25 阅读
  7. 掌握JVM调优:如何在Gradle中配置JVM参数?

    2024-07-18 08:44:01       19 阅读
  8. vue2.0中如何实现数据监听

    2024-07-18 08:44:01       20 阅读