前言程序员
做为一名优秀的程序员,必须保证本身的代码能提供正确的,完善的接口,如此方能和同事,甲方更好的沟通合做,也让本身的代码更加地容易维护。函数
本文将介绍一些设计优秀接口的思路。编码
思路一:导入新的类型spa
下面仍是先看这个例子,我定义了一个存储日期的 Date 类:设计
1 class Date 2 { 3 public: 4 Date(int month, int day, int year); 5 // ...... 6 };
可用如下方法定义一个 Date 对象:指针
1 Date d(30, 3, 1995);
可有些用户会犯很蠢的错误,好比:code
1 Date d(30, 3, 1995);
显然,他用户将接口的参数输错位了。然而,优秀的接口应当可以友好反馈错误信息给用户,这种状况下,最好的策略就是定义新的类型,请参考下面这个 Date 类的设计:对象
1 class Day 2 { 3 public: 4 explicit Day(int d) 5 :val(d) {} 6 // ...... 7 private: 8 int val; 9 }; 10 11 class Month 12 { 13 public: 14 static Month Jan() { 15 return Month(1); 16 } 17 static Month Feb() { 18 return Month(2); 19 } 20 // ...... 21 22 private: 23 explicit Month(int m) { 24 val = m; 25 } 26 // ...... 27 28 int val; 29 // ...... 30 }; 31 32 class Year 33 { 34 public: 35 explicit Year(int y) 36 :val(y) {} 37 private: 38 int val; 39 };
而定义一个 Date 对象,可采用以下方式:blog
1 Date d(Month::Feb(), Day(30), Year(1995));
在日,月,年各个类中,还能够实现更高级的封装。继承
思路二:引导用户进行正确编码
这里继续上一篇文章中提到的智能指针的一个例子,这里要说明的是,当时给出的那个工厂函数:
1 class Investment 2 { 3 // ...... 4 }; 5 6 Investment * createInvestment();
并非很好的一种设计。
为啥?由于用户可能忘了使用智能指针把 Investment * 接过去。而使用下面的工厂函数接口设计能够有效的避免这个问题:
1 std::tr1::shared_ptr<Investment> createInvestment();
这样就让用户你不用智能指针都不行了,哈哈。
甚至你还能够更过度,指定智能指针在资源被指数为0的时候要调用的析构函数:
1 std::tr1::shared_ptr<Investment> createInvestment() 2 { 3 // 指定智能指针类型及删除器 4 std::tr1::shared_ptr<Investment>retVal (static_cast<Investment *>(0), getRidOfInvestment); 5 6 // retVal = ... 7 // 令 retVal 指向正确的对象 8 9 return retVal; 10 }
上段代码中的getRidOfInvestment是你本身指定的删除器。
思路三:限制类型什么事情能够作什么事情不能作
使用 const,explicit等限制性关键字,屏蔽无用的拷贝构造函数等能够作到这点。
这些在之前的文章中均有讲解。
思路四:使你的类尽可能表现得像内置类型
要作到这点可不简单,你须要以"当初语言设计者设计语言内置类型时"那般谨慎的思考class的设计,对设计出的class,咱们须要问本身如下几个问题:
1. 新的对象资源在什么时候建立? 什么时候销毁?
这部分一样涉及到构造函数,析构函数的编写。
2. 对象的初始化和赋值应该有什么样的差异?
这部分涉及到构造函数,拷贝构造函数,赋值运算符的编写。不要混淆这两个概念。
3. 若是对象发生了值传递,意味着什么?
你得仔细考虑这期间发生的资源相关的一些问题。
4. 哪些对象是合法范畴?
对象的成员是否是合法,这点很重要。它影响到了你诸多成员函数的错误检查工做,也影响到了抛出的异常。
5. 新的类需不须要配合某个继承图系?
若是这个类的子类要实现多态,那么成员函数就得声明为虚函数;若是这个类继承自其它类,那么当你自定义拷贝构造函数或者重载赋值运算符的时候,也得对父类部分作出处理。
6. 什么样的操做符和函数对这个新的类型来讲是合理的?
须要考虑这个类型应该对哪些运算符重载,还有哪些函数被当作成员函数,哪些用非成员函数实现。
具体的选取规则,之后会有篇文章专门讲。
7. 什么样的标准函数应当驳回?
将它声明为 private
8. 新的类型成员将被哪些对象取用?
这个涉及到变量private,protected,以及友元相关机制。
9. 新的类型是否应当知足通常化的要求?
若是你要定义的是一个类家族,那么你须要的不止是一个类,而是一个类模板
小结
1. 类的设计不要贪快。要尽可能知足,实现这些规则,贪快会致使开发后期事倍功半。
2. 本文应当在实际项目中进行类设计的时候边设计边看,如此,方能有显著的提升。