代码整洁之道精华——第六章 对象和数据结构

本文探讨了编写整洁代码的重要性,并对比了面向对象编程与过程式编程在维护性和扩展性方面的差异。文章强调了对象与数据结构之间的本质区别,以及遵循德墨忒尔律的原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

阅读本文有两种原因:第一,你是个程序员;第二,你想成为更好的程序员。你如果想成为更好的程序员,那就请细细品味文章内容,它绝不会让你失望。
代码整洁之道教给大家如何编写整洁的代码,而不仅仅是能运行的代码,这对于编程者而言很重要。我在读这本书的第一遍时没什么感觉,但在读第二遍时觉得它确实挺不错的,如果有机会的话我还会读第三遍。下面是我在读书过程中摘录的精华内容,希望大家认真对待。各位看官如果读完本文觉得书中的精华内容挺合自己的胃口,那就可以抽出时间认真地读一下这本书。

1、对象把数据隐藏于抽象之后,暴露操作数据的函数。数据结构暴露其数据,没有提供有意义的函数。回头再读一遍,留意这两种定义的本质。他们是对立的,这种差异貌似渺小,但却有深远的意义。
2、对象与数据结构的二分原理:
过程式代码(使用数据结构的代码)便于在不改动既有数据结构的前提下添加新函数。面向对象代码便于在不改动既有函数的前提下添加新类。
反过来讲也说得通:
过程式代码难以添加新的数据结构,因为必须修改所有函数。面向对象代码难以添加新函数,因为必须修改所有类。

过程式代码示例:

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 topLeft;
    public double radius;
}

public class Geometry{
    public double PI = 3.1415926;
    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 r.width*r.height;
        }
        else if(shape instanceof Circle){
            Circle c = (Circle)shape;
            return PI*c.radius*c.radius;
        }
        throw new NoSuchShapeException();
    }
}

如果此时想在Geometry类中添加一个primeter()函数,这实现起来很简单,现有形状不会因此而受影响。

public class Geometry{
    public double PI = 3.1415926;
    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 r.width*r.height;
        }
        else if(shape instanceof Circle){
            Circle c = (Circle)shape;
            return PI*c.radius*c.radius;
        }
        throw new NoSuchShapeException();
    }

    public double primeter(Object shape)throws NoSuchShapeException
    {   if(shape instanceof Square){
            Square s = (Square)shape;
            return 4*s.side;
        }
        else if(shape instanceof Rectangle){
            Rectangle r = (Rectangle)shape;
            return r.width*2+r.height*2;
        }
        else if(shape instanceof Circle){
            Circle c = (Circle)shape;
            return 2*PI*c.radius;
        }
        throw new NoSuchShapeException();
    }
}

如果此时想添加一个新形状,那Geometry类中的area()和primeter()都要修改,如果Geometry类中有其他方法的话,那要修改的类可能会更多。
所以说过程式代码难以添加新的数据结构,因为必须修改所有函数。

面向对象代码示例:

public class Square implements Shape{
    private Point topLeft;
    private double side;

    public double area(){
        return side*side;
    }
}

public class Rectangle implements Shape{
    private Point topLeft;
    private double height;
    private double width;

    public double area(){
        return height*width;
    }
}

public class Circle implements Shape{
    private Point topLeft;
    private double radius;
    public double PI = 3.1415926;

    public double area(){
        return PI*radius*radius;
    }
}

如果此时想添加一个新形状,这实现起来很简单,现有形状不会因此而受影响。

public class Square implements Shape{
    private Point topLeft;
    private double side;

    public double area(){
        return side*side;
    }
}

public class Rectangle implements Shape{
    private Point topLeft;
    private double height;
    private double width;

    public double area(){
        return height*width;
    }
}

public class Circle implements Shape{
    private Point topLeft;
    private double radius;
    public double PI = 3.1415926;

    public double area(){
        return PI*radius*radius;
    }
}

public class NewShape implements Shape{
    private Point topLeft;
    ......

    public double area(){
        ......
    }
}

如果此时想添加一个primeter()函数,那就要修改Shape接口,继承了Shape接口的现有形状也全部需要修改。
所以说面向对象代码难以添加新函数,因为必须修改所有类。
3、著名的德墨忒尔律认为:模块不应该了解他所操作对象的内部情况。对象隐藏数据,暴露操作,这意味着对象不应该通过存取器暴露其内部结构。
德墨忒尔律认为,类C的方法f只应调用以下对象的方法:

  • C
  • 由f创建的对象
  • 作为参数传递给f的对象
  • 由C的实体变量持有的对象

如果数据结构只简单地拥有公共变量,没有函数,而对象拥有私有变量和公共函数,那这个问题就不容易混淆。
4、每个单元(对象或方法)应当对其他单元只拥有有限的了解。
举例说明:
a. 假设我在便利店购物。付款时,我是应该将钱包交给收银员,让她打开并取出钱?还是我直接将钱递给她?
b. 人可以命令一条狗行走,但是不应该直接指挥狗的腿行走,应该由狗去指挥控制他的腿如何行走。

抛开所有细节不不谈,代码整洁之道总体来说可以分为以下7点:

  • 运行所有测试
  • 减少重复代码
  • 提高表达力
  • 提早构建简单抽象
  • 类和方法都只做好一件事
  • 尽量减少类和方法的数量
  • 努力,让营地比你来时更干净。努力,让世界比你来时更干净。努力,让代码比你签出时更干净。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

changuncle

若恰好帮到您,请随心打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值