设计原则
单一职责原则(Single Responsibility Principle)
- 更容易测试:具有一种职责的类将具有更少的测试用例,从而导致测试工作量大大减少。
- 松耦合 : 单个类中的功能越少,依赖性就越少。因此,它将降低耦合。
- 更容易读 : 较小的、组织良好的类比较大的类更容易被初次阅读代码的人搜索到。
- 更容易使用 :减少了错误的数量,提高了开发速度,并使你作为程序员,上班摸鱼的时间大大的增加。
- 更容易维护: 通过确保您的类只有一个责任,您可以节省大量开发应用程序的工作并创建更易于维护的体系结构。
过度使用单一职责原则的缺点
- 增加代码的数量:因为需要分解一个大类为多个小类。当每个小类功能都比较简单时,类的数量将会显著增加,使得代码量更大。
- 增加代码的复杂度:严格遵循单一职责原则并不总是可能的,有时候职责之间的联系是紧密的,分离职责会使得代码的逻辑更加复杂。
-
增加开发、维护成本:过度分解一个大类为多个小类可能会增加系统的开发和维护的成本,需要仔细权衡利弊。
单一职责原则:比如有一个检查当前状态的结构体这个函数,把视频和图片统一按视频去处理,同时检查完之后,比如时间出错了,文件段的序号出错了,他又调用对应的恢复函数,然后这个恢复的函数又会调用修改的函数写进硬盘里。相当于这个名为检查的函数干了检查,恢复,修改这三个的功能,一开始我修改起来很难。不够单从当时编写代码的角度来考虑,我想是有几个优点的。他把图片和视频在很多函数中是统一处理的,直接强转成视频的结构体,因为前面一部分重要的信息是相同的,直接用就可以了,同时他函数的复用率是比较高的,这点是拿易读和结构做了一定的牺牲。我把他分开了,让一个函数尽量干他命名的事情,也方便后面维护。虽然整体代码量会多一些,但更加易读,同时你就算删了这个函数也没问题,整个功能都能跑通,但是你原来就不行,因为他还有一些结构体里的状态字在里面发生了改变。
接口隔离原则(Interface Segregation Principle)
接口隔离原则就是客户端不应该依赖它不需要的接口,或者说类间的依赖关系应该建立在最小的接口上。
- 一个类对另一个类的依赖应该建立在最小接口之上。
- 建立单一接口,不要建立庞大臃肿的接口。
- 尽量细化接口,接口中的方法尽量少(适度)。
对于一个把数据写进硬盘的操作函数来说,如果现在新加进来一种结构,比如原来是视频,图片,现在加进来ai便签了,你需要改这个写操作的函数为了支持他,而视频和图片用不上这新加进来代码,那这个接口隔离就做的不够好了,可以再细化一层,让最后的写操作不会受到新加进来的数据结构的影响。其实就有点像linux的write函数了。
开闭原则(Open Closed Principle)
开闭原则才是精髓,其他五个都是对他的具体实现。一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。也就是说,我们应该通过扩展来实现软件功能的增加,而不是通过修改现有代码来实现,这样可以提高软件的稳定性和可复用性。
在C语言中,我们可以利用函数指针、接口结构体实现开闭原则。无论是利用函数指针还是接口结构体,实现开闭原则的核心思路都是将可变部分抽象出来,从而达到避免修改代码而扩展功能的目的。
适当使用开闭原则的优点
- 可扩展性:遵循开闭原则,软件系统可以更容易地添加新的功能模块,而不会对原有模块产生任何影响。
- 可维护性:遵循开闭原则的代码更容易维护。因为修改一个软件设计时需要充分考虑该代码对其他模块的影响,迫使程序员写出更加模块化、可维护的代码。
- 代码复用:开闭原则可以鼓励我们构建一个可重用、通用的代码库,因为新的需求只需要扩展而不需要更改原有代码。
- 提高软件质量:遵循开闭原则可以使得代码更加灵活,不需要修改原有的代码,只需要增加新的代码,有利于提高软件质量。
过度使用开闭原则的缺点
- 增加代码的复杂度:开闭原则可能导致代码过度设计,过多的使用抽象和接口,增加代码复杂度。
-
增加开发时间及成本:在某些情况下,为了扩展一个软件实体,需要大量的代码重构。这在一些情况下是必要的,但在其他情况下可能会增加开发时间和成本。
这个我在业务代码中也有看到过符合这样的设计,通过封装结构体,在里面放回调函数实现,比如一个函数要检测码流是否正常,码流有网络码流,本地码流。我需要通过回调传给他不同的函数就能在一个对外接口上实现扩展,以后还有别的码流,传进去对应的处理码流的函数就可以了,其实这个整体的实现也属于是依赖倒置原则了
里氏替换原则(Liskov Substitution Principle)
LSP要求在软件代码中,父类对象出现的地方被替换成子类可以无差错的运行。换言之,引用基类的地方必须能够透明的使用子类对象,行为不会改变。
- 继承体系模塑的应该是IS-A关系,比如猫是一种动物,子类对象可以完全替代父类对象。
- 应把基类设计成抽象类,而非具象类;应从抽象类派生子类,而不应从具象类继承。
- 子类应该实现父类的抽象方法,而不应该重写父类的已实现方法。
- 子类可以扩充新的功能,而不应该改变父类已有的功能。
- 子类不能增添任何父类没有的附加约束。
虚函数是一种C++中常用的实现里氏替换原则的方法。在C语言中也可以通过函数指针来模拟虚函数的实现。我们可以定义一个父类结构体,其中包含一些函数指针,子类可以根据自己的需求指向不同的函数,从而实现不同的行为,这也是一种里氏替换原则的应用。
迪米特法则(Law of Demeter),又叫“最少知道法则”
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中的一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
大主管和主管,主管和开发人员
这个我倒没有多少理解,因为c语言中主要通过尽量少的对外接口实现这个功能,尽量将方法定义成static,这是我个人的理解
依赖倒置原则(Dependence Inversion Principle)
依赖倒置:就是要依赖于抽象,不要依赖于具体。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
适当应用依赖倒置原则的优点
- 降低了模块之间的耦合度:提高了系统的灵活性和可维护性;
- 提高了代码的可读性:通过面向抽象编程,让代码更加易于理解;
- 降低了开发的难度:提高了开发的效率;
过度使用依赖倒置原则的缺点
- 可能会增加代码的复杂度和难度:需要在设计和实现的过程中进行充分考虑和把握;
- 影响代码开发效率:需要合理规划抽象接口的设计,过于精细的接口设计可能会影响代码的效率和开发效率;
这个例子是和师傅是看到相关代码讨论的时候聊的,具体是设备中有有线网卡,wifi网卡,4G网卡。当有线和wifi其中一个连接后,要关掉4g。
设计1:在4g模块中判断有线和无线是否连接,4g连接模块直接就依赖了这两个模块了。
设计2:抽象出一个其他网卡接口,其他网卡连接时,则退出4g模块
设计3:再从业务上分析,业务的本质时要不要开启4g,如果以后为了高码率视频引入了5g网卡,那对外的接口就要修改了,可以对外提供一个enable接口。这样就不需要依赖其他接口了。
设计4:把4g功能放到网络状态管理框架里,及网卡切换时。关闭优先级低的网卡,相当于是把4g放到了优先级最低了。
