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

2024-08-25 20:36

本文主要是介绍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)数据成员和成员函数放到一个类定义中,这样的话,就会把类的实现细节暴露给了用户。

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

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

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

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

这篇关于C++学习笔记----5、重用之设计(一)---- 重用的哲学的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1106591

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名