【复读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)等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值