C++学习笔记----5、重用之设计(二)---- 为最优化重用结构化你的代码(1)

news2024/9/20 12:16:13

        一定要在所有的层面在设计的一开始就考虑重用,也就是说,从一个独立的函数到一个类,直到整个库与框架。我们以后就把这些统称为部件。下面的策略会帮助你正确地组织代码。记住所有的这些策略关注的是你的代码的的通用目的。设计可重用代码第二个方面就是提供易用性,与接口设计关联度更大,以后会详细讨论。

1、避免将无关或者逻辑上独立的概念组合在一起

        当设计一个组件时,应该将重点放在一个单独的任务或者一组任务上,也就是说,应该努力做到高内聚。这就是著名的单一职责原则SRP。不要将例如随机数生成器与XML解析器这样的无关的概念组合在一起。

        即使不是将代码设计用来重用的,也要牢记这个原则。整个程序很少自己重用。事实是,程序的部分或者子系统会直接整合进其他应用中或者应用于轻微不同的程序。这样,你应该设计程序使其逻辑上分隔成单独的功能组件,以便在不同的程序中重用。每个这样的部件应该具有定义好的责任。

        这种程序策略模型化了真实世界的独立的、可交换部件的设计原则。例如,你可以写一个Car类,将引擎的所有属性与行为放置其中。然而,引擎是单独的部件,没有与汽车的其他方面绑在一起。引擎可以从一辆汽车中移出,再把它放到其他汽车中。合适的设计应该是Engine类包含了引擎特定的功能。Car实例只是包含了一个Engine的一个实例。

2、将程序划分为逻辑子系统

        应该将子系统设计成独立的部件,可以独立重用,也就是说,要做到低耦合。例如,如果你在设计一个网络游戏,切将网络与图形用户界面划分在不同的子系统中。这样的话,你就可以重用任一部件而不用把其他的代码拉进来。例如,你可能想要写一个非网络的游戏,这样的话你可以重用图形用户界面子系统而不需要网络部分。同样的,你可以设计一个点对点的文件共享程序,这种情况下你就可以重用网络子系统而不需要图形用户界面的功能。

        要确保在每一个子系统中遵从抽象原则。把每一个子系统想象成一个原型的库,都要提供一个清楚易懂又易用的界面。即使是只有你一个人使用这些原型库,也会从这些设计良好的界面与单一功能逻辑分离的实现中获益非浅。

3、使用类层次结构来分隔逻辑概念

        将程序分隔成逻辑子系统,应该避免在类层次上将无关概念组合在一起。例如,假设你要为自动驾驶汽车写一个类。决定以一个基本的汽车类开始,然后将自动驾驶的逻辑直接整合进来。然而,如果你只是要写一个非自动驾驶的汽车的程序呢?这种情况下,所有与自动驾驶的逻辑都没有用了,并且要求你的程序去与本来可以避免的类库相连接,比如vision库、LIDRAR库等等。一个可能的解决方案就是生成一个类层次结构,一个自动驾驶的汽车派生于一个通用的汽车。这样的话,就可以在程序中使用汽车基类,而不需要自动驾驶的能力,也就不需要加上这种算法的支出了。下图所示即为该层次结构:

        这种策略在有两个逻辑概念时会比较好使,比如自动驾驶和汽车。当有三个或更多的概念时就会变得非常复杂。例如,假设你要提供卡车与汽车,每个都会要求自动驾驶或者不自动驾驶。逻辑上,卡车与汽车都是交通工具,所以它们可以是vehicle类的派生类,如下图所示:

        同样的,自动驾驶类可以是非自动驾驶类的派生类。无法将其进行线性层次结构的划分。一种可能就是将自动驾驶功能做成一个混合类。前面的博文使用多重继承在C++中实现混合类。例如,一个PictureButton可以是继承自Image类与Clickable类的混合类。然而,对于自动驾驶设计来说,最好是使用一种不同的混合类实现,使用类模板。

        对于类模板,我们还没有详细讨论过,不过,对于我们目前讨论的东西,其细节并不重要。当然了,对于继承的讨论也不够详细,同样的,其细节对于我们这个案例的讨论也不重要。你只需要知道Derived类继承/派生自Base类就够了:

class Derived : public Base {};

        SelfDrivable混合类模板定义如下:

template <typename T>
class SelfDrivable : public T
{
};

        SelfDrivable混合类提供了实现自动驾驶功能的所有需要的算法。一旦有了SelfDrivable混合类模板,你就可以如下所示实例化一辆汽车各一辆卡车:

SelfDrivable<Car> selfDrivingCar;
SelfDrivable<Truck> selfDrivingTruck;

        这两行代码的结果就是编译器使用SelfDrivable混合类模板生成一个实例,类模板中的T被Car替换,因此就从Car派生,另一个T被Truck替换,因此派生自Truck。以后我们再详细讨论混合类。

        这种解决方案要求你写四个不同的类(Vehicle,Car,Truck和SelfDrivable),但是对于功能清晰的划分值得这种努力 。

        同样的,也应该避免无关的概念组合在一起,也就是说,高内聚,不仅仅是在类的层次,在设计的任何层次,都应该避免。例如,在成员函数的层次,一个单独的成员函数不应该执行逻辑无关的事情,混合交互(set)与检测(get)等等。

4、使用聚合划分逻辑概念

        聚合,我们前面讨论过,模型化了组合关系:对象包含了其他对象以执行一些功能特点。前面也不止一次强调,如果可以选择的话,尽量使用组合关系,而避免使用继承关系。

        例如,假设你要写一个FamilyTree类来保存家庭成员。很明显,树结构对于保存此类信息是理想的。不要将树结构的代码直接整合进FamilyTree类中,应该写一个单独的Tree类。FamilyTree类可以包含并且使用Tree实例。用面向对象的术语,就是FamilyTree组合了Tree。使用此技巧,树结构可以在另外的程序中更容易地重用。

5、消除用户接口依赖性

        如果你的库是一个数据操作库,想要将数据操作与用户界面分隔开。这就意味着这类库你永远不要假设哪类用户界面会用到此类库。库也不要使用任何标准控制台输出与输入功能,像std::println()或者cin,因为如果该库用于图形用户界面,这样做就毫无意义。例如,一个Windows GUI的应用通常不会有任何形式的控制台I/O。如果你认为库只用于GUI应用,依然不要弹出任何类型的消息框或者其他类型的提示给到最终用户,因为这是用户代码要实现的功能。是用户代码要决定怎么将信息展示给用户。这种类型的依赖不但使得可重用性差,也使得用户代码无法正确响应错误,例如,静态处理错误信息等。

        MVC模式,我们以前讨论过,是一个非常著名的将数据与展示分隔开的设计模式。使用此模式,模型可以位于库中,用户代码可以提供视图与控制器。

6、对于通用数据结构和算法使用模板

        C++有一个概念叫做模板,允许你生成通用类型与类的结构。例如,你可能写过一个整型数组的代码,后来想要一个双浮点数数组,你就需要重写并复制所有用双浮点数的代码。模板就能将刚才所说的整型或双浮点型的规格变成参数,可以生成一个用于任何类型的代码块。模板允许你写用于任何类型的数据结构与算法。

        我们前面讨论过std::vector类,它是C++标准库的一部分。要生成一个整型的vector,可以写std::vector<int>;要生成双浮点型的vector,可以写std::vector<double>。一般来说,模板编程,非常强大但比较复杂。幸运的是,生成较简单的根据类型进行参数化的模板使用还是可能的。与我们今天所讨论的主题无关的模板的细节以后再讨论,比如写我们自己的模板等。

        只要有可能,就应该使用数据结构与算法的通用设计,而不要将其代码化到特定的程序中。不要写一个只保存书对象的平衡二叉树结构。要使其通用化,使其可以保存任何类型的对象。这样的话,你就可以将其用于书店,音响店,操作系统,或者任何需要平衡二叉树的地方。该策略在标准库中大量存在,提供了用于任何类型的通用数据结构与算法。

        然而,同时要记住的是,实现通用数据结构相比于非通用数据结构的实现要花费更多的时间。要更多地考虑一下需求,要用许多不同的类型进行更广泛的通用实现的测试。如果你的数据结构过于特殊,可能会得不偿失,这样的话,是否考虑用一个更简单的非通用数据结构的实现会更好。所以,在编程领域,没有金科玉律,只有不断实践,在实践中总结出来的,什么是性价比最好 的,性价比最好的,就是你想要的最终的代码设计。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2075621.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024上半年营业收入同比增长17%,一图看懂亚信安全2024半年报

2024上半年营业收入同比增长17%&#xff0c;贯彻健康经营&#xff0c;业绩企稳向好&#xff01; 云网安筑基 AI智绘未来 | 一图看懂亚信安全2024半年报

SAP DRC 交易与报表合规化

交易与报表合规化- SAP Document and Reporting Compliance(DRC) SAP DRC通过嵌入到端到端业务流程的源系统中的国家和地区特定内容&#xff0c;保证全球处理合规&#xff1b;利用统一的解决方案管理全球电子发票和法定报表&#xff0c;从而优化合规性&#xff0c;提高效率并提…

无线麦克风什么牌子最好,无线直播麦克风十大名牌推荐

​在数字化飞速发展的今天&#xff0c;无线领夹麦克风已经成为自媒体创作者、直播主播和专业录音师的重要工具。它们不仅小巧便携、操作简便&#xff0c;还具有出色的录音质量&#xff0c;极大地提升了音频录制的效率和质量。无论是户外探险的Vlog拍摄&#xff0c;还是室内直播…

基于Linux系统和ncurses库的贪吃蛇小游戏

目录 前言 一、地图&#xff0c;蛇身&#xff0c;食物设计 二、蛇和食物的初始化 食物 蛇 三、添加和删除蛇身节点 四、main函数和蛇运行方向线程 五、地图刷新线程 最终源码 前言 ncurses库是什么我并没有深入了解&#xff0c;本文的重点也不是ncurses的使用&#xff…

BUUCTF PWN wp--pwn1_sctf_2016

第一步 checksec&#xff0c;并检查该题的保护机制&#xff0c;32位 Arch: i386-32-little 这表示程序的架构是32位的i386&#xff08;即x86&#xff09;&#xff0c;并且使用小端序&#xff08;little-endian&#xff09;存储方式。这意味着程序是为32位系统设计的。RELRO: Pa…

期权末日轮行情即将来临!注意两个操作更好盈利!

今天带你了解期权末日轮行情即将来临&#xff01;注意两个操作更好盈利&#xff01;期权末日轮&#xff0c;就是指在期权合约到期前的最后几天&#xff0c;比如50ETF期权品种的到期日是每个月第四个星期的星期三&#xff0c;那么在最后一个星期就有可能发生末日轮行情了。 末日…

Linux安装Navicat Premium

一、安装Navicat Premium17 1、下载安装包 https://www.navicat.com.cn/download/navicat-premium#linux 2、赋执行权限 //假设安装包在/etc/navicat目录下 cd /etc/navicat chmod x navicat17-premium-cs-x86_64.AppImage 3、启动应用程序 ./navicat17-premium-cs-x86_64…

python.exe -m pip install --upgrade pip报错解决

引言 在执行命令的时候&#xff0c;提示可以更新版本 [notice] A new release of pip is available: 24.1.2 -> 24.2 [notice] To update, run: python.exe -m pip install --upgrade pip按照提示&#xff0c;直接使用 python.exe -m pip install --upgrade pip 命令进行更…

Cocos Creator2D游戏开发(15)---预制体和按钮的绑定以及冷却效果的实现

场景: 植物大战僵尸中,种植植物前,要判断状态,只有在阳光充足时才能点击 图片资源: 预制体的创建,创建一个空节点命名: CardTemplate,将三张豌豆射手相关的图片拖入 如下图 其中card_mask图片中的透明度改为150; 在assets中创建prefab文件夹,将CardTemplate节点直接拖入pre…

openGauss——体系结构

一、体系结构概览 二、驱动程序 客户端程序使用驱动程序&#xff0c;向openGauss的后端管理线程GaussMaster发起连接请求。openGauss目前支持以下四种驱动程序&#xff1a; JDBC&#xff0c;用于Java连接ODBC&#xff0c;开放数据库互连Libpq&#xff0c;C语言程序接口Psycop…

SpringMvc 以配置类的形式代替xml文件

1、配置类 1.1、创建Mvc 项目之后创建 MyWebApplicationInitializer 类 实现接口 WebApplicationInitializer public class MyWebApplicationInitializer implements WebApplicationInitializer {Overridepublic void onStartup(ServletContext servletContext) throws Serv…

大数据-101 Spark Streaming DStream转换 窗口操作状态 跟踪操作 附带多个案例

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

windows安装pytorch精简版(英伟达GPU)

1 下载anaconda 官网:Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 选择下载Anaconda-1.4.0-Windows-x86.exe 2 创建虚拟环境 以管理员身份打开Anaconda Prompt conda env list conda creat -n yolov8 python3.8 创建过程中有提示,填…

【图文详解】idea码云环境搭建

公众号&#xff1a;墨轩学习网-----B站&#xff1a;墨轩大楼 欢迎关注&#xff01;&#xff01;&#xff01; 一、码云简介 目前开源中国的四大框架&#xff0c;即四条产品线&#xff1a;开源中国社区、众包、码云和招聘。 码云是开源中国推出的基于Git的代码托管服务&#…

鸿蒙HarmonyOS开发:创建新的Lite工程

当开始开发一个应用/服务时&#xff0c;首先需要根据工程创建向导&#xff0c;创建一个新的工程&#xff0c;工具会自动生成对应的代码和资源模板。 说明 在运行DevEco Studio工程时&#xff0c;建议每一个运行窗口有2GB以上的可用内存空间。 创建和配置新工程 DevEco Studio提…

如何应对市场变革的战略利器之敏捷企业架构实践全景指南

敏捷与企业架构融合的必然性 在全球化和数字化的双重推动下&#xff0c;市场竞争的激烈程度前所未有。企业必须迅速适应市场的变化&#xff0c;以在激烈的竞争中脱颖而出。然而&#xff0c;传统的企业架构往往侧重于长期战略规划&#xff0c;尽管它在维持企业的稳定性方面功不…

阿贝云评测:免费虚拟主机与免费云服务器的优势对比

阿贝云作为一家知名云服务提供商&#xff0c;以其稳定可靠的服务质量在业界享有盛誉。其中&#xff0c;其免费虚拟主机和免费云服务器备受用户喜爱。在这篇评测中&#xff0c;我们将对这两种服务进行详细对比。 首先&#xff0c;就免费虚拟主机而言&#xff0c;阿贝云提供的免费…

图片工具箱:一键批量加水印,守护创意,提升效率!

前言 你是否曾在处理海量图片时&#xff0c;被繁琐的步骤和漫长的等待时间折磨得苦不堪言&#xff1f;是否梦想过拥有一款神器&#xff0c;能让你的图片处理工作变得轻松愉快&#xff0c;从此告别加班的烦恼&#xff0c;迎接升职加薪的曙光&#xff1f;那么&#xff0c;让我向…

我主编的电子技术实验手册(18)——认识电感

本专栏是笔者主编教材&#xff08;图0所示&#xff09;的电子版&#xff0c;依托简易的元器件和仪表安排了30多个实验&#xff0c;主要面向经费不太充足的中高职院校。每个实验都安排了必不可少的【预习知识】&#xff0c;精心设计的【实验步骤】&#xff0c;全面丰富的【思考习…

Golang学习笔记-Golang中的锁

同步原语和锁 Golang作为一个原生支持用户态的语言&#xff0c;当提到并发进程&#xff0c;多线程的时候&#xff0c;是离不开锁的&#xff0c;锁是一种并发编程中的同步原语&#xff08;Synchronization Primitives&#xff09;&#xff0c;它能保证多个 Goroutine 在访问同一…