微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

解释 Robin C. Martin 关于过程式编程 vs OOP 的“干净代码”

如何解决解释 Robin C. Martin 关于过程式编程 vs OOP 的“干净代码”

Robin C. Martin 的“干净的代码”有一个关于过程编程与面向对象编程的部分,其中提出了一些我无法理解的陈述。 有人愿意更详细地解释这些陈述背后的思考过程吗?

声明如下:

过程代码(使用数据结构的代码)使得在不改变现有数据结构的情况下轻松添加函数。另一方面,OO 代码可以轻松添加新类,而无需更改现有功能

补语也是对的:

程序代码很难添加新的数据结构,因为所有的功能都必须改变。 OO 代码很难添加函数,因为所有类都必须更改。

用于证明此语句的代码示例如下。

程序代码示例:

public class Square {
  public Point topLeft;
  public double side;
}

public class Rectangle {
  public Point topLeft;
  public double height;
  public double width;
}

public class Circle {
  public Point center;
  public double radius;
}

public class Geometry {
  public final double PI = 3.14;
  
  public double area(Object shape) throws NoSuchShapeException {
    if (shape instanceof Square) {
      Square s = (Square) shape;
      return s.side * s.side;
    }
    else if (shape instanceof Rectangle) {
      Rectangle r = (Rectangle) shape;
      return s.height * s.width;
    }
    else if (shape instanceof Circle) {
      Circle c = (Circle) shape;
      return PI * c.radius * c.radius;
    }
    throw new NoSuchShapeException();
  }
}

现在,让我们在这里暂停一下。让我们假设 Geometry 不仅计算面积,还计算周长。按照上面的例子,很明显:

  • 添加新形状将强制更改几何中的所有函数(面积、边界等)。不过,现有的数据结构不需要更改,它们只是数据的容器。
  • 向 Geometry 添加函数(例如周长)很容易。

因此,Procedural 使添加函数变得容易,但添加新数据结构变得困难。

但是让我们考虑一下上面的例子,它是用所有典型的过程语言 C 编写的。 使用 C,我们无法编写一个函数,例如采用抽象数据类型的 Geometry's area。相反,我们将使用以下方法签名:

int geometry_area(square s)
int geometry_area(rectangle r)
int geometry_area(circle c)

int geometry_perimeter(square s)
int geometry_perimeter(rectangle r)
int geometry_perimeter(circle c)

考虑到这一点,添加一个新的形状并不会强制改变任何功能,这与作者所说的相矛盾。取而代之的是,我们必须在其独立函数中为新形状实现所有行为

改为添加新行为,将迫使我们为所有现有形状编写函数

所以,总的来说,我对作者推理背后的逻辑有点困惑。

作者总结如下:

在任何复杂的系统中,有时我们想要添加新的数据类型而不是新的函数。对于这些被反对的情况,OO 是最合适的。另一方面,有时我们会想要添加函数而不是数据类型。在这种情况下,程序代码和数据结构会更合适。

解决方法

您正在谈论第 6 章 - 对象和数据结构,小节数据/对象反对称。

我认为书中的方法故意使用面向对象的语言来展示他所说的“反对称”。您正在尝试使用过程语言 C 来遵循他的论点。

你可以用 C 重构书中的例子。

#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <memory.h>

#define M_PI 3.14159265358979323846

typedef enum {
    RECTANGLE   = 0x0,CIRCLE      = 0x1
} geometry_type_t;


typedef struct {
    geometry_type_t type;
} geometry_t;

//radius in millimeters to avoid floats
typedef struct {
    int radius;
} circle_t;

//width and height in millimeters to avoid floats
typedef struct {
    int width;
    int height;
} rectangle_t;

int geometry_area(geometry_t* geometry) {
    if (geometry->type == RECTANGLE) {
        rectangle_t* rect = (rectangle_t*)(geometry + 1);
        return (rect->height * rect->width);
    }
    else if (geometry->type == CIRCLE) {
        circle_t* circle = (circle_t*)(geometry + 1);
        //I don't care about floatings in this example
        return (circle->radius * circle->radius * M_PI);
    }
}

int main(int argc,char* argv[]) {
    circle_t c;
    c.radius = 2000; //millimeters

    geometry_t* geom = malloc(sizeof(geometry_t) + sizeof(circle_t));
    if (geom == NULL) {
        return EXIT_FAILURE;
    }
    geom->type = CIRCLE;

    memcpy((geom + 1),&c,sizeof(circle_t));
    printf("Area of circle with radius %d: %d\n",c.radius,geometry_area(geom));

    rectangle_t r;
    r.height = 1000;
    r.width = 2000;
    geom->type = RECTANGLE;
    memcpy((geom + 1),&r,sizeof(rectangle_t));
    printf("Area of rectangle with width %d and height %d: %d",r.width,r.height,geometry_area(geom));
}

如果您遵循您提到的方法,为书中的每个 shape 短语提供单独的函数:

... if I add a new shape,I must change all the functions in Geometry to deal with it

可以改写为:

adding a new shape forces you to reimplement any associated function for that specific shape

还有声明:

... if a perimeter() function were added to Geometry. The shape classes would be unaffected

可以改写为:

adding a new function for multiple structs needs to be done individually for each struct

在我看来作者的解释只有在使用某种抽象时才有意义。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?