• 对象和数据结构



    前言

    代码整洁之道读书随笔,第六章


    一、从链式调用说起

    面向对象语言中常用的一种调用形式,链式调用,是一种较受推崇的编码风格,如果你调用一个实例的方法,修改了实例的状态,后续需要调用其他方法,进一步改变实例的状态,那么不需要每次都用变量接收返回值,直接链式调用即可。

    例如gorm的更新可以这样实现。

    result := m.tx.Model(&model.A{}).Where(&model.A{ID: id}).Updates(data)
    
    • 1

    其中Where的实现为:

    // Where return a new relation, filter records with given conditions, accepts `map`, `struct` or `string` as conditions, refer http://jinzhu.github.io/gorm/crud.html#query
    func (s *DB) Where(query interface{}, args ...interface{}) *DB {
    	return s.clone().search.Where(query, args...).db
    }
    
    • 1
    • 2
    • 3
    • 4

    二、数据抽象

    Java的初级程序员,此处特指刚入行时的本人,喜欢为类的私有成员变量加getter/setter,在很多crud场景,其实也感觉不出有什么问题,直到你的业务场景不再满足简单的crud,例如,书中的示例中给出了一个笛卡尔平面上一个point类的实现。刚好我现在的工作就是为智能机器人做路径规划,所以对这个感触就比较深。
    一个点包含X/Y轴,每次改变位置,我们不能只更新单个轴,而是要同时更新,同样,查询也不是只想查询到单个轴,那么分别为每个变量加getter/setter是没有意义的。
    getter/setter的根本目的是为了隐藏实现,隐藏实现是为了让用户无需了解实现就可以操作数据本体。

    三、数据、对象的反对称性

    对象和数据结构之间的二分原理:

    过程式代码(使用数据结构的代码)便于在不改动既有数据结构的前提下添加新函数;面向对象代码便于在不改动既有函数的前提下添加新类。
    反过来:
    过程式代码难以添加新数据结构,因为必须修改所有函数;面向对象代码难以添加新函数,因为必须修改所有类。

    那么我们可以举例,对于机器人,如果要构造一个类,那么就可以考虑,如果你的抽象级别在机器人上,每个机器人有自己的行为,比如a类机器人是聊天机器人,b类机器人是扫地机器人,那么就做面向对象,你不需要每次增加新功能都为所有机器人增加新函数。
    但是如果你们机器人都是扫地机器人,那么把能力进行抽象就是比较正确的选择,走路的能力抽象成接口,让机器人组合能力,对于走路这个能力就成了过程式代码,就算你需要增加新的机器人种类,只需要包含这种能力即可。

    四、得墨忒尔律

    模块不应了解它所操作对象的内部情形。

    更准确的,类C的方法f只应该调用以下对象的方法。

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

    书中给出了一个反例:

    final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
    
    • 1

    现在和开头我说的链式调用比较一下,链式调用的每次调用返回的都是类C的实例本身,那么是没有违背得墨忒尔律的,但是这个反例中,每次返回的都是不一样的对象,那么对于调用者就需要了解Options、ScratchDir的内部构造结构。

    特别需要指出,这里Options、ScratchDir特指拥有行为的对象,如果他们只拥有变量,而不拥有行为,那么作者认为不需要考虑得墨忒尔律。
    结合outputDir的使用:

    String outFile = outputDir + "/" + className.replace('.', '/') + ".class";
    FileOutputStream fout = new FileOutputStream(outFile);
    BufferedOutputStream bos = new BufferedOutputStream(fout);
    
    • 1
    • 2
    • 3

    作者给出了修正结果:

    BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);
    
    • 1

    把过程隐藏到createScratchFileStream() 中,对于调用者,就不需要了解过多类的细节。

    五、数据传送对象

    数据传送对象(Data Transfer Objects, DTO)是用于与数据库通信或解析套接字传递的消息等场景中的数据结构,不适合加入业务逻辑。Active Record1是一种特殊的DTO。


    总结

    这是代码整洁之道第六章的读书随笔,本章已完结。


    1. Active Record(活动记录),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。 ↩︎

  • 相关阅读:
    嵌入式Linux驱动开发 01:基础开发与使用
    PyTorch学习笔记-完整训练模型的方法
    如何新建一个一台交换机下连两个PC的拓扑
    SSM+基于SSM的智慧社区宠物医院 毕业设计-附源码211621
    是谁在Go标准库的源码中植入了色情网站?
    设置基站IP及设置基站连接服务器
    python ==True和is True有什么区别?(python单例对象True、False、None)(is和==和is)
    设计模式-08-适配器模式
    node版本管理工具nvm
    Open3D(C++) 深度图像与彩色图像转三维点云
  • 原文地址:https://blog.csdn.net/i973635025/article/details/134475026