C++学习笔记----5、重用之设计(一)---- 重用的哲学

        设计的代码你和其他的程序员应该都可以重用。这条规则不但适用于让其他程序员特别使用的库与框架,也适用于任何类、子系统或者为程序设计的部件。一定要记住如下的格言:

  • 一次编写,多次使用。
  • 尽量避免重复代码
  • 不要重复你自己。

原因如下:

  • 很少有代码只在一个程序中使用。要确信你的代码不管怎么样都会被再次使用,所以一开始就要正确地进行设计。
  • 设计重用的代码可以节省时间与金钱。如果你设计的代码不考虑未来的使用,当你碰到 类似功能的需求时,就会花费大量的时间重新造轮子。
  • 其他程序员一定能够使用你写的代码。你不会一个人在一个项目中工作。同事会感激你提供的良好设计,打包功能的库以及代码的努力。重用的设计也可以被叫做合作编码。
  • 缺乏重用就会有代码重复;代码重复就会造成维护梦魇。如果在一个重复的代码中发现了bug,就需要在它重复的所有地方进行修复。如果你发现自己在复制粘贴代码,就必须至少要考虑一下是否可以提炼到一个函数或类中。
  • 你是自己工作最大的受益者。有经验的程序员从来不会摒弃代码。随着时间的推移,他们建立了一个不断演化的个人库。你永远不会知道将来你会需要类似功能的代码。

        当然了,我喜欢这么说,对于重用,不可避免地会涉及到知识产权的问题。这个问题其实与我们学习C++编程无关,是另外一个领域的话题,我只是要说明,为公司干的工作成果,其知识产权是公司的,离职后对这些代码的重用一定要基于合法的前提。但与我们要讲的重用之哲学其实不矛盾,你不这么认为么?

如何设计可重用的代码

        可重用的代码完成如下两个目标:

  • 首先,是要对稍微不同的目的或者在不同的应用域中一般够用。特定应用的带有细节的部件在其它程序中重用是困难的。
  • 其次,可重用的代码也是易用的。不需要花费太长的时间去理解其接口与功能。程序员必须能够逐渐将其整合进他们的应用。

        将库交付给用户的方式也很重要。可以以源代码的方式交付,客户只需要将你的源代码整合进他们的项目中即可。另一种方式就是以静态库的方式交付二进制代码,链接进他们的应用,或者是用动态库的方式,在Windows环境下是.dll文件,在Linux环境下是.so文件。不同的交付方式对于如何设计可重用的代码的限制是不一样的。

        设计可重用的代码最重要的策略就是抽象。

使用抽象

        抽象的关键就是将接口与实现进行了隔离。实现就是你要写的代码,去完成你要完成的任务。接口就是其他人使用你的代码的方式。在C中,头文件揭示了你要在接口中写的库的函数声明。在面向对象的程序设计中,可以公开访问的类成员函数与类属性就是类的接口。然而,一个好的接口应该只包含公共的成员函数。类的属性永远不要变成公共的,但是可以通过公共的成员函数来向外部暴露。公共成员函数也叫做get()与set()。

        以前我们介绍过抽象的原则,讲过一个真实世界中的对于电视的分析,你可以在不理解其内部是如何工作的情况下通过接口赤使用。同样的,在设计代码时,也要将实现与接口清楚地分开。这种分隔使代码易于使用,主要是因为用户不需要理解内部实现的细节就可以使用其功能。

        使用抽象对你与使用你的代码的用户都有好处。用户有好处是因为他们不需要担心实现细节;可以在不理解代码怎么干活的情况下利用其功能。这样的话,就可以不要求用户改变其使用的情况下升级你的代码。对于动态链接库,用户甚至不需要重新构建其可执行程序。最后,对双方都有好处是因为,对于你,库作者,可以指定接口,按照你想要的交互,以及你想要的支持功能来指定。对于接口与实现的隔离或以防止用户以你不想要的方式来使用库,因为这种使用方式可能会引起不可预知的行为和问题。

        设计接口时,不要向用户暴露实现细节。

        有时候库会要求用户代码保留从一个接口返回的信息并将其传递给另一个。这种信息有时候会叫做一个句柄,常用于在不同的调用之间跟踪特定实例的状态。真实世界的例子就是OpenGL,一个2D/3D优化库。OpenGL的许多函数返回句柄,操作句柄,以GLuint的类型出现。例如,如果你要用OpenGL函数glGenBuffers()来生成一个缓存,它返回GLuint句柄。任何时候你要调用另一个函数来结这个缓存进行操作的时候,都必须把GLuint句柄传递给那个函数。

        如果你的库设计需要一个句柄,不要暴露其内部。使其成为一个透明的类,程序员无法访问其内部数据成员,不管是直接还是通过get()与set(),都不行。不要要求用户代码在句柄内部调整变量。不好的设计例子就是要求在一个假定透明的句柄中指定特定结构成员的值,比如为了打开错误日志。

        不幸的是,C++对于类的抽象原则很不友好(当然了,从另一个角度来说,它提供了方便性)。语法要求你将public接口与non-public(private或者protected)数据成员和成员函数放到一个类定义中,这样的话,就会把类的实现细节暴露给了用户。

        抽象是如此重要,以至于它要在整个设计中对你进行指导。你所做出的每一个决定,都要问问你自己,你的选择是否遵从了抽象的原则。站在用户的角度来决定是否在接口中包含了内部实现的知识细节。可能,很偶尔地,你会破坏这个规则。

        当使用抽象原则进行可重用代码设计时,应该侧重于以下几点:

  • 首先,必须正确结构化代码。要使用什么样的类层次结构?要用模板吗?如何将代码分成子系统?
  • 其次,要设计接口,该接口就是进入库进行你提供的功能访问的入口。

好了,我们今天讨论的内容不少了,上面的这两个主题我们以后继续聊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王俊山IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值