优雅的对象

本文探讨了面向对象设计的核心思想,强调了封装的重要性,提倡对象间的尊重和信任。作者认为对象应是自洽、不可变的实体,避免可变性、静态方法和NULL,以提高代码的可维护性。同时,提倡使用短小简洁的类,减少公共方法,避免类型检查和强制转换,以及利用不可变性增强软件的稳定性。文中还提到了声明式编程的优势,鼓励程序员站在更高抽象层面思考问题。

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

最近一口气读完了二百多页的《Elegant Objects》。可能因为整理自博客所以排版一般,而且才二百多页定价却40多刀。但读过之后发现超值,甚至还想去买第二卷。作者观点大多比较激进,对自己的理念异常坚定,所以经常使用诸如“绝对不要使用XXX”、“记住XXX,就这样,句号”。但作者绝不故弄玄虚,在批判之后,一定会给出自己的建议和代码示例。除去个别章节个人觉得很有争议,大部分内容读过之后都是很震撼的。另外原书观点较为零散,为了方便感兴趣的同学继续阅读学习,本文重点部分都标注了与原书章节的对应。

Elegant Object


1.面向对象思想

面向对象思想与此前“远古”时期编程思想的不同就是:我们站在更高的抽象上思考问题,从问题领域出发定义概念和概念间的关系,而不再是以机器指令为中心,想尽各种办法指挥机器去做事。作者极力想要扭转我们的思想,不要被机器同化,总是从它的角度来思考问题,而是忘记具体的底层架构、指令、编程语言,让以我们要解决的问题为中心。

此外书中作者反复强调的一点就是:一切都是为了可维护性。这可能是工程里的编程与科学里的计算的主要区别之一。作为软件工程的一环,除了基本的正确性外,最重要的一点就是可维护性了。因为现实世界的不确定,需求的反复变化,代码量巨大等问题,没有良好的可维护性的话。以可维护性为中心出发,作者指出了面向对象的三大癌症:可变性、静态方法、NULL。就像《黑客帝国》里说的人类是地球的癌症,这三者就是我们日常开发的混乱之源。而且某种程度上,三者背后的思想都根植于面向过程编程。


2.概念的封装

对象不是一堆由我们调用者决定调用顺序的函数集合,依次调用操作其内部封装的数据。作者反复用拟人的方式强调,这种指手画脚地方式是对“别人”的不尊重。我们去餐厅点菜,不会跟厨师说你得先做这个再做那个,这样做出来才好吃。现实中我们直接说,请给我来一份这个菜,厨师会自己决定如何烹饪。跟一个对象打交道也是如此,对象是一个自洽的、能自己做决定并自己行动的实体,就像一个能自给自足(self-sufficient)的生物一样。所以说,对象与对象之间相互“尊重信任”的关系是面向对象思想的核心

2.1 设计者:隐藏好你的抽象

从对象设计者角度,要自重,不要泄漏你的实现细节,不要泄漏任何内部抽象。从这个角度来说,setter/getter也是邪恶的(原书3.5节)。你可能会说,setter/getter不是远好于直接暴露成员变量吗?而且它还是Java Bean的标准,我们还可以在里面添加数据验证、甚至改变存储内容方式等逻辑。但这都不重要,重要的是对于调用者来说这与直接的数据访问没什么区别。比如下面Cash类中如果加上一个getDollars()方法,那就好像让调用者对自己说:“去成员数据里找,看看有没有一个叫dollars的,把它返回给我”。而dollars()则会好一些,仿佛在说:“请告诉我你有多少美元?”(另可参考原书的2.4节 Choose method names carefully,作者对方法起名的见解)。

此外也不要返回NULL造成空指针异常,失去调用者对你的信任(原书4.1节 Never return NULL)。返回NULL的最常见情况就是找不到调用者想要的对象,那么可选的其他方式有返回空列表/集合,如果只是要返回一个单一对象的话则可采用空对象设计模式,或者在必要时抛出异常。更深层的原因是NULL不应该出现在面向对象的世界里(原书3.3节 Never accept NULL arguments)。

也不要因为方便而对外提供成员常量,比如public static final String CRLF = "\r\n",看似很常见却破坏了面向对象的理念(原书2.5节 Don’t use public constants)。下面将这部分逻辑封装到CRLFString类中,我们再也不用担心明天要为不同平台添加不同的换行符了。但这会导致很多类不是么,参见第三部分关于短小而简单的类设计理念的讨论。

class CRLFString {
    private final String src;
    CRLFString(String src) {
        this.src = src;
    }
    String toString() {
        if (/* this is windows */) {
            //...
        }
        return String.format("%s\r\n", src);
    }
}

2.2 使用者:Show Your Respect

从使用者角度,不要去偷窥,比如利用反射技术在运行时获取对象内部的信息,比如最常用的instanceof判断对象是否是某个具体的子类等等(原书3.7节 Avoid type introspection and casting)。可能你会说你很少用反射,也可以尽量不用,但单元测试里的mock技术是无人不知、无人不晓的。mock难道不是很好的技术吗?现在已经有了很多非常棒的mock框架。

class Cash {
    private final Exchange exchange;
    private final int cents;
    public Cash(Exchange exchange, int cents) {
        this.exchange = exchange;
        
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值