C++ C语言实现的坚实原则

C++ C语言实现的坚实原则,c++,c,c++11,solid-principles,design-principles,C++,C,C++11,Solid Principles,Design Principles,我知道坚实的原则是为面向对象语言编写的 我在Robert Martin的《嵌入式C的测试驱动开发》一书中找到了本书最后一章中的以下句子: “应用开闭原理和Liskov替换原理可使设计更加灵活。” 这是一本C(无C++或C)的书,应该有一条实现这一原则的方法。< /P> 在C语言中实现这一原则有任何标准的方法?我能想到的最接近我头脑的事情(它不是完美的,所以如果有人有更好的想法,欢迎他们向我推荐)主要是在我为某种库编写函数的时候 对于Liskov替换,如果您有一个定义了多个函数的头文件,那么您不希

我知道坚实的原则是为面向对象语言编写的

我在Robert Martin的《嵌入式C的测试驱动开发》一书中找到了本书最后一章中的以下句子:

“应用开闭原理和Liskov替换原理可使设计更加灵活。”

<>这是一本C(无C++或C)的书,应该有一条实现这一原则的方法。< /P>
在C语言中实现这一原则有任何标准的方法?

我能想到的最接近我头脑的事情(它不是完美的,所以如果有人有更好的想法,欢迎他们向我推荐)主要是在我为某种库编写函数的时候

对于Liskov替换,如果您有一个定义了多个函数的头文件,那么您不希望该库的功能取决于您使用的函数实现;您应该能够使用任何合理的实现,并期望您的程序能够完成它的任务


至于打开/关闭原则,如果您想要实现一个I/O库,那么您需要具有尽可能少的功能(例如
读取
写入
)。同时,您可能希望使用这些功能开发更复杂的I/O功能(如
scanf
printf
),但您不会修改达到最低限度的代码。

开放-关闭原则指出,系统的设计应使其开放可扩展,同时保持关闭不被修改,或者可以在不修改的情况下使用和扩展。Dennis提到的I/O子系统是一个相当常见的例子:在可重用系统中,用户应该能够指定如何读取和写入数据,而不是假设数据只能写入文件

实现这一点的方法取决于您的需要:您可以允许用户传入一个打开的文件描述符或句柄,该描述符或句柄已经允许在文件之外使用套接字或管道。或者,您可以允许用户传递指向应该用于读写的函数的指针:这样,除了操作系统允许的情况外,您的系统还可以用于加密或压缩的数据流

Liskov替换原则指出,应该始终可以用子类型替换类型。在C语言中,通常没有子类型,但可以在模块级应用这一原则:代码的设计应确保使用模块的扩展版本(如较新版本)不会破坏它。模块的扩展版本可能会使用比原始版本包含更多字段的
struct
enum
中包含更多字段等类似内容,因此您的代码不应假定传入的结构具有特定大小,或枚举值具有特定最大值


其中一个例子是如何在BSD套接字API中实现套接字地址:有一个“抽象”套接字类型
struct sockaddr
,可以代表任何套接字地址类型,每个实现都有一个具体的套接字类型,例如用于Unix域套接字的
struct sockaddr\u un
,以及用于IP套接字的
struct sockaddr\u in
。在套接字地址上工作的函数必须被传递一个指针,指向数据和具体地址类型的大小。

首先,考虑一下为什么我们有这些设计原则。为什么遵循坚实的原则会使软件变得更好?努力理解每项原则的目标,而不仅仅是在特定语言中使用这些原则所需的具体实现细节

  • 单一责任原则通过增加 凝聚性更好的模块化可以提高可测试性, 可用性和可重用性
  • 打开/关闭原则通过以下方式实现异步部署: 将实现彼此分离
  • Liskov替换原则通过以下方式促进模块化和模块重用: 确保其接口的兼容性
  • 界面分离原理减少了界面之间的耦合 界面的无关使用者,同时提高可读性和 可理解性
  • 依赖项反转原理减少了耦合,并且具有很强的可扩展性 支持可测试性
请注意每个原则是如何推动系统某个属性的改进的,无论是更高的内聚性、更松散的耦合性还是模块性

记住,您的目标是生产高质量的软件。质量由许多不同的属性组成,包括正确性、效率、可维护性、可理解性等。当遵循这些属性时,坚实的原则将帮助您达到目标。因此,一旦您了解了原则的“为什么”,实现的“如何”就会变得容易得多

编辑:

我会尽量更直接地回答你的问题

对于打开/关闭原则,规则是旧接口的签名和行为在任何更改之前和之后都必须保持不变。不要中断任何调用它的代码。这意味着完全需要一个新接口来实现新东西,因为旧东西已经有了行为。新接口必须具有不同的签名,因为它提供了新的和不同的功能。所以你在C中满足这些要求就像你在C++中那样做。 假设您有一个函数
intfoo(inta,intb,intc)
,您想添加一个几乎完全相同的版本,但它需要第四个参数,如下所示:
intfoo(inta,intb,intc,intd)
。要求新版本与旧版本向后兼容,并且新参数的某些默认值(如零)将实现这一点。您可以将实现代码从旧的foo移动到新的foo中,并在旧的foo中执行以下操作:
#include <stdio.h>
void fred(int x)
{
    printf( "fred %d\n", x );
}
void barney(int x)
{
    printf( "barney %d\n", x );
}

#define Wilma 0
#define Betty 1

int main()
{

    void (*flintstone)(int);

    int wife = Betty;
    switch(wife)
    {
    case Wilma:
        flintstone = &fred;
    case Betty:
        flintstone = &barney;
    }

    (*flintstone)(42);

    return 0;
}