你会如何设计一个抽象类,比如说,表示具有特定属性的磁盘上的文件?假设你需要能够检查文件是否存在于磁盘上或已被删除。你会首先创建一个对象,然后调用其exists()
方法吗?还是你会首先调用Disk.fileExists()
,只有在返回TRUE
的情况下才创建File
类的实例并继续使用它?这可能听起来像是一种品味问题,但实际上并不那么简单。
让我们看看如何在不同的编程语言及其SDK中检查文件是否存在于磁盘上:
基本上有两种不同的设计决策:要么您首先创建一个 File
对象,然后询问它在磁盘上是否存在,要么您询问磁盘文件是否存在,然后才创建 File
类的实例。哪种设计更好?让我们暂时忘记静态方法是不好的,想象一下 Files
不是一个实用类,而是一个磁盘的抽象。如果您是为新编程语言设计新 SDK 的设计师,您将如何设计 exists()
方法?
要回答这个问题,我们必须回答一个更基本的问题:通过将 exists()
方法放在 File
上还是放在 Disk
上,SDK 将向程序员传达什么信息?
对于一位经验丰富的程序员来说,这可能听起来像一个琐碎而表面的问题,但让我说服您这并非如此。考虑数据库中的付款账单列表的设计。账单可以是“已付款”或“尚未付款”,程序员可以通过 paid()
方法进行检查。第一个设计选择是这样的(这是 Java):
第二个选择是以下内容:
第一个片段中的信息是什么?我认为是这样的:“账单可能已支付,也可能未支付。”第二个设计选项中的信息是什么?是这样的:“如果账单存在,则已支付。”换句话说,在第一个片段中,账单的两个特性(“我存在”和“我已支付”)共存,而在第二个片段中,它们被合并为一个(“我已支付”)。
在持久层,这种特性的二分法可能意味着在SQL数据库表中的一个可空列paid
,或者一个具有NOT NULL
约束的列。第一个片段可能会返回一个在数据库中存在为一行的bill
对象,但paid
列被设置为NULL
。使用您设计的程序员可以轻松理解账单的“已支付”状态的概念:它并不同于其存在的状态。程序员必须先获取账单,然后再检查其付款状态。程序员还期望可能出现两个失败点—账单可能不存在,或账单可能未支付—会抛出不同的异常或返回不同类型的结果。
正如您所看到的,这个问题不只是表面问题,而是非常存在的:Bill
或Bills
方法的设计有助于程序员了解账单存在的条件。
现在,关于文件的exists()
方法的原始问题的答案很容易找到。在磁盘上找到文件是第一个任务,它检查文件名是否正确,文件在磁盘上可能存在。
然后,检查文件在磁盘上的存在情况:
我们现在可以得出结论,Python、JS、Ruby等许多编程语言让我们检查硬盘上文件是否存在的方法是错误的。JDK 6是正确的,但JDK 8的发明者却毁了它(很可能是为了性能考虑)。
顺便说一句,在许多其他编程语言中还有许多不同的“文件检查”设计决策的例子。
Translated by ChatGPT gpt-3.5-turbo/42 on 2024-07-08 at 05:14