未命名 1
在软件架构设计中,理解**接口(Interface)和抽象类(Abstract Class)**的区别是消除代码混乱的关键。结合你当前的项目结构(AbstractStorage 与 BunS3Storage),以下是它们的详细对比以及关于“继承”与“实现”的界定:
1. 抽象类 vs 接口:本质区别
| 特性 | 接口 (Interface) | 抽象类 (Abstract Class) |
|---|---|---|
| 本质意义 | 能力的定义(能做什么)。它是一份契约,规定了外部调用的标准。 | 事物的抽象(是什么)。它是多个具体子类的共性提取。 |
| 代码复用 | 不能包含逻辑。只能定义方法名、参数和返回值(在 TS 中)。 | 可以包含逻辑。可以编写通用的代码供子类直接使用。 |
| 成员变量 | 不能定义实例变量(只能定义类型)。 | 可以定义并存储状态(如 this.config)。 |
| 多继承 | 一个类可以实现多个接口。 | 一个类只能继承一个抽象类。 |
2. 哪些是“实现”,哪些是“继承”?
在你的代码库中,这两个概念分别对应以下结构:
继承 (Inheritance / Extends)
“继承”用于子类与父类之间。 当你希望子类自动拥有父类已经写好的方法时,使用继承。
-
代码体现:使用关键字
extends。 -
你的项目示例:
-
BunS3Storage继承了AbstractImageStorage。 -
OSSStorage继承了AbstractStorage。 -
含义:
BunS3Storage是AbstractImageStorage的一种,它自动获得了父类中generateUniqueFileName和validateFileSize等已经写好的通用工具方法。
-
实现 (Implementation / Implements)
“实现”用于类与接口之间。 当你定义了一个标准,要求不同的类必须按照这个标准提供功能时,使用实现。
-
代码体现:使用关键字
implements(虽然在你目前的 TS 代码中多采用直接继承抽象类的方式)。 -
你的项目示例(如果你采用了
IStorage方案):-
BunS3StorageImpl实现了IStorage接口。 -
含义:
IStorage规定了必须有upload方法,BunS3StorageImpl保证提供这个方法的具体代码。
-
3. 在你项目中的实际应用建议
你之前的代码之所以感觉“混乱”,是因为你在继承关系上做了重复:
-
抽象类(继承的源头):
-
AbstractStorage提供了基础的文件处理逻辑,如processFileData。 -
AbstractImageStorage也提供了类似的逻辑,如generateUniqueFileName。 -
建议:保留一个
AbstractStorage即可。
-
-
具体类(实现者/继承者):
-
BunS3Storage和LocalStorage应该直接继承自唯一的抽象类AbstractStorage。 -
它们通过重写(Override)父类的抽象方法(如
uploadFile)来提供具体实现。
-
总结
-
如果你想定义标准(比如:所有存储插件都必须有上传和删除功能),用接口或抽象类中的抽象方法。
-
如果你想少写重复代码(比如:阿里云和本地存储都要生成随机文件名),把这段代码写在抽象类里,让子类去继承它。
在现代 TypeScript 开发中,通常直接使用一个抽象类作为顶层设计(如你的 AbstractStorage),因为它既能定义标准(抽象方法),又能复用代码(普通方法),比单纯的接口更实用。