网易首页 > 网易号 > 正文 申请入驻

【软件设计】TypeScript 中的 SOLID 原则

0
分享至

了解有关 TypeScript 中 SOLID 原则的更多信息

TypeScript 对用 JavaScript 编写干净的代码产生了巨大的影响。但总有改进的方法,编写更好、更简洁的代码的一个重要方法是遵循由 Robert C. Martin(也称为 Uncle Bob)发明的所谓 SOLID 设计原则。
在本文中,我将通过使用 TypeScript 编写的示例向您介绍这些原则。我已经在这个 Github 存储库上部署了所有示例。

单一职责原则 (SRP)


“一个类改变的原因不应该超过一个。”


一个类应该有一个目的/责任,因此只有一个改变的理由。遵循这一原则可以更好地维护代码并最大限度地减少潜在的副作用。


在以下不好的示例中,您会看到如何存在多重责任。首先,我们为一本书建模,而且,我们将这本书保存为一个文件。我们在这里遇到了两个目的:

class Book {
public title: string;
public author: string;
public description: string;
public pages: number;

// constructor and other methods

public saveToFile(): void {
// some fs.write method to save book to file
}
}

第二个示例向您展示了如何通过遵循单一职责原则来处理这个问题。我们最终有两个类,而不是只有一个类。每个目的一个。


class Book {
public title: string;
public author: string;
public description: string;
public pages: number;

// constructor and other methods
}

class Persistence {
public saveToFile(book: Book): void {
// some fs.write method to save book to file
}
}

开闭原则 (OCP)

“软件实体……应该对扩展开放,但对修改关闭。”


与其重写你的类,不如扩展它。通过不接触旧代码的新功能应该很容易扩展代码。例如,实现一个接口或类在这里非常有帮助。


在下一个示例中,您将看到错误的操作方式。我们使用了名为 AreaCalculator 的第三个类来计算 Rectangle 和 Circle 类的面积。想象一下我们稍后会添加另一个形状,这意味着我们需要创建一个新类,在这种情况下,我们还需要修改 AreaCalculator 类以计算新类的面积。这违反了开闭原则。
我们来看一下:

class Rectangle {
public width: number;
public height: number;

constructor(width: number, height: number) {
this.width = width;
this.height = height;
}
}

class Circle {
public radius: number;

constructor(radius: number) {
this.radius = radius;
}
}

class AreaCalculator {
public calculateRectangleArea(rectangle: Rectangle): number {
return rectangle.width * rectangle.height;
}

public calculateCircleArea(circle: Circle): number {
return Math.PI * (circle.radius * circle.radius);
}
}

那么,我们可以做些什么来改进这段代码呢?为了遵循开闭原则,我们只需添加一个名为 Shape 的接口,因此每个形状类(矩形、圆形等)都可以通过实现它来依赖该接口。这样,我们可以将 AreaCalculator 类简化为一个带参数的函数,而这个参数是基于我们刚刚创建的接口。

interface Shape {
calculateArea(): number;

class Rectangle implements Shape {
public width: number;
public height: number;

constructor(width: number, height: number) {
this.width = width;
this.height = height;
}

public calculateArea(): number {
return this.width * this.height;
}
}

class Circle implements Shape {
public radius: number;

constructor(radius: number) {
this.radius = radius;
}

public calculateArea(): number {
return Math.PI * (this.radius * this.radius);
}
}

class AreaCalculator {
public calculateArea(shape: Shape): number {
return shape.calculateArea();
}
}

里氏替换原则 (LSP)

“使用指向基类的指针或引用的函数必须能够在不知情的情况下使用派生类的对象。”


使用指向上层类的指针或引用的下层类必须能够在不知情的情况下使用派生类的对象。这些低级类应该只是扩展上级类,而不是改变它。


那么我们在下一个坏例子中看到了什么?我们上了两节课。Square 类扩展了 Rectangle 类。但正如我们所见,这个扩展没有任何意义,因为我们通过覆盖属性宽度和高度来改变逻辑。

class Rectangle {
public width: number;
public height: number;

constructor(width: number, height: number) {
this.width = width;
this.height = height;
}

public calculateArea(): number {
return this.width * this.height;
}
}

class Square extends Rectangle {
public _width: number;
public _height: number;

constructor(width: number, height: number) {
super(width, height);

this._width = width;
this._height = height;
}
}

因此,我们不需要覆盖,而是简单地删除 Square 类并将其逻辑带到 Rectangle 类而不改变其用途。

class Rectangle {
public width: number;
public height: number;

constructor(width: number, height: number) {
this.width = width;
this.height = height;
}

public calculateArea(): number {
return this.width * this.height;
}

public isSquare(): boolean {
return this.width === this.height;
}
}

接口隔离原则

“许多特定于客户端的接口都比一个通用接口好。”


简单地说,更多的接口总比接口少的好。让我解释下一个不好的例子。
我们有一个名为 Troll 的类,它实现了一个名为 Character 的接口。但是由于我们的巨魔既不会游泳也不会说话,这个角色界面似乎不适合我们的类。

interface Character {
shoot(): void;
swim(): void;
talk(): void;
dance(): void;

class Troll implements Character {
public shoot(): void {
// some method
}

public swim(): void {
// a troll can't swim
}

public talk(): void {
// a troll can't talk
}

public dance(): void {
// some method
}
}

那么我们可以通过遵循这个特定的原则来做些什么呢?我们删除了 Character 接口并将其功能拆分为四个接口,并且仅将我们的 Troll 类依赖于我们实际需要的这些接口。

interface Talker {
talk(): void;

interface Shooter {
shoot(): void;
}

interface Swimmer {
swim(): void;
}

interface Dancer {
dance(): void;
}

class Troll implements Shooter, Dancer {
public shoot(): void {
// some method
}

public dance(): void {
// some method
}
}

依赖倒置原则(DIP)

“取决于抽象,[不是]具体。”


这到底是什么意思,对吧?嗯,其实很简单。让我们揭开它的神秘面纱!
在这个糟糕的例子中,我们有一个 SoftwareProject 类,它初始化 FrontendDeveloper 和 BackendDeveloper 类。但这是错误的方式,因为这两个类彼此非常相似,我的意思是,它们应该做类似的事情。因此,为了实现依赖倒置原则的目标,有更好的方法来满足需求。

class FrontendDeveloper {
public writeHtmlCode(): void {
// some method

class BackendDeveloper {
public writeTypeScriptCode(): void {
// some method
}
}

class SoftwareProject {
public frontendDeveloper: FrontendDeveloper;
public backendDeveloper: BackendDeveloper;

constructor() {
this.frontendDeveloper = new FrontendDeveloper();
this.backendDeveloper = new BackendDeveloper();
}

public createProject(): void {
this.frontendDeveloper.writeHtmlCode();
this.backendDeveloper.writeTypeScriptCode();
}
}

那么我们该怎么办呢?正如我所说,它实际上非常简单,而且更容易,因为我们之前已经学习了所有其他原则。
首先,我们创建一个名为 Developer 的接口,由于 FrontendDeveloper 和 BackendDeveloper 是相似的类,我们依赖于 Developer 接口。
我们不是在 SoftwareProject 类中以单一方式初始化 FrontendDeveloper 和 BackendDeveloper,而是将它们作为一个列表来遍历它们,以便调用每个 develop() 方法。

interface Developer {
develop(): void;

class FrontendDeveloper implements Developer {
public develop(): void {
this.writeHtmlCode();
}

private writeHtmlCode(): void {
// some method
}
}

class BackendDeveloper implements Developer {
public develop(): void {
this.writeTypeScriptCode();
}

private writeTypeScriptCode(): void {
// some method
}
}

class SoftwareProject {
public developers: Developer[];

public createProject(): void {
this.developers.forEach((developer: Developer) => {
developer.develop();
});
}
}

感谢您阅读我关于 Medium 的第一篇文章。我希望,我已经能够刷新你的知识。您可以在 Wikipedia 上阅读有关 SOLID 的更多信息。

本文 https://jiagoushi.pro/solid-principles-typescript 讨论:知识星球【首席架构师圈】或者加微信小号【cea_csa_cto】或者加QQ群【792862318】 公众号

【jiagoushipro】
【超级架构师】
精彩图文详解架构方法论,架构实践,技术原理,技术趋势。
我们在等你,赶快扫描关注吧。

【cea_csa_cto】
50000人社区,讨论:企业架构,云计算,大数据,数据科学,物联网,人工智能,安全,全栈开发,DevOps,数字化.

QQ群

【792862318】深度交流企业架构,业务架构,应用架构,数据架构,技术架构,集成架构,安全架构。以及大数据,云计算,物联网,人工智能等各种新兴技术。
加QQ群,有珍贵的报告和干货资料分享。

视频号 【超级架构师】
1分钟快速了解架构相关的基本概念,模型,方法,经验。
每天1分钟,架构心中熟。

知识星球 向大咖提问,近距离接触,或者获得私密资料分享。

喜马拉雅 路上或者车上了解最新黑科技资讯,架构心得。 知识星球 认识更多朋友,职场和技术闲聊。 微博 【智能时刻】 哔哩哔哩 【超级架构师】

抖音 【cea_cio】超级架构师

快手 【cea_cio_cto】超级架构师

小红书 【cea_csa_cto】超级架构师

谢谢大家关注,转发,点赞和点在看。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
赵本山长子赵铁蛋因病去世,女儿成网红,亿万家产会花落谁家?

赵本山长子赵铁蛋因病去世,女儿成网红,亿万家产会花落谁家?

林雁飞
2026-01-13 17:31:12
只能赌一把麦基!广东队有望补强内线群,萨林杰也要留队?

只能赌一把麦基!广东队有望补强内线群,萨林杰也要留队?

绯雨儿
2026-01-31 13:40:36
人社部重磅定调!养老金涨幅锁定2%,高龄老人优先受益

人社部重磅定调!养老金涨幅锁定2%,高龄老人优先受益

万物知识圈
2026-01-30 09:02:08
四十加:不适合幼态,御姐熟到发光

四十加:不适合幼态,御姐熟到发光

飛娱日记
2026-01-26 12:28:23
75年,一名县委书记连跳几级,升为广东省委书记,由邓公亲自提拔

75年,一名县委书记连跳几级,升为广东省委书记,由邓公亲自提拔

舆图看世界
2026-01-31 13:35:03
孟鹤堂用半年商演的全部收入,买了件38万的蟒袍送给郭德纲。

孟鹤堂用半年商演的全部收入,买了件38万的蟒袍送给郭德纲。

荆楚寰宇文枢
2026-01-25 23:08:14
这一夜,穿深V的宋佳 全裹出镜的高圆圆,输给了蓬头垢面的董明珠

这一夜,穿深V的宋佳 全裹出镜的高圆圆,输给了蓬头垢面的董明珠

杨仔述
2026-01-29 18:44:57
100.9万!奔驰官宣:新车正式发布

100.9万!奔驰官宣:新车正式发布

高科技爱好者
2026-01-30 23:10:56
71岁成龙自曝患ADHD,求问“怎样才能集中精力”;罗永浩也备受此病困扰:服药10多年

71岁成龙自曝患ADHD,求问“怎样才能集中精力”;罗永浩也备受此病困扰:服药10多年

环球网资讯
2026-01-30 16:49:12
“上午立春春节暖,下午立春倒春寒”,2026立春在几点?有啥说法

“上午立春春节暖,下午立春倒春寒”,2026立春在几点?有啥说法

老特有话说
2026-01-28 16:44:22
逼广东队裁掉奎因?CBA强力中锋制霸内线,或成杜锋最大的对手!

逼广东队裁掉奎因?CBA强力中锋制霸内线,或成杜锋最大的对手!

绯雨儿
2026-01-31 13:37:05
他是演艺圈“渣爹代表”,人到中年一炮而红,戏外却是女儿奴

他是演艺圈“渣爹代表”,人到中年一炮而红,戏外却是女儿奴

以茶带书
2026-01-31 18:02:18
提前受死?美军公海挑衅中国海军,不料先手优势几秒内就丧失

提前受死?美军公海挑衅中国海军,不料先手优势几秒内就丧失

卷史
2026-01-28 10:32:16
武汉市民建议拆除多条BRT车道,官方回复!

武汉市民建议拆除多条BRT车道,官方回复!

三农老历
2026-01-31 16:15:19
逆天,公司发布通知:加班期间禁止猝死,违者罚款500元!

逆天,公司发布通知:加班期间禁止猝死,违者罚款500元!

黯泉
2026-01-30 22:50:02
中超热身赛:北京国安2-1中甲球队,法比奥破门,新援拉莫斯现身

中超热身赛:北京国安2-1中甲球队,法比奥破门,新援拉莫斯现身

中超伪球迷
2026-01-31 17:18:50
春节不忙乱,这3道菜提前备好,简单一热就上桌,省事好吃寓意好

春节不忙乱,这3道菜提前备好,简单一热就上桌,省事好吃寓意好

江江食研社
2026-01-27 20:30:03
过气男顶流沦为酒局“工具人”!全程讨好、倒酒赔笑,像一个商品

过气男顶流沦为酒局“工具人”!全程讨好、倒酒赔笑,像一个商品

涵豆说娱
2026-01-19 18:16:27
国民党率团赴京,郑丽文对大陆称呼变了,蔡英文不排除再度出马

国民党率团赴京,郑丽文对大陆称呼变了,蔡英文不排除再度出马

史料布籍
2026-01-30 13:42:59
回国了我才敢说:委内瑞拉,是我去过的所有国家中,最被看轻的!

回国了我才敢说:委内瑞拉,是我去过的所有国家中,最被看轻的!

阿纂看事
2026-01-09 09:48:35
2026-01-31 19:23:00
架构师研究会
架构师研究会
全网【架构师研究会】大数据,云,物联网,智能计算
1240文章数 4332关注度
往期回顾 全部

科技要闻

SpaceX申请部署百万卫星 打造太空数据中心

头条要闻

巴拿马港口运营合同被裁定违宪长和股价大跌 港府表态

头条要闻

巴拿马港口运营合同被裁定违宪长和股价大跌 港府表态

体育要闻

新时代得分王!东皇37+三双刷7纪录怒吼释放

娱乐要闻

业内下场了!金晨构成逃逸事实应该予以处罚

财经要闻

白银,暴跌!黄金,40年最大跌幅!

汽车要闻

新款宾利欧陆GT S/GTC S官图发布 V8混动加持

态度原创

亲子
艺术
家居
数码
军事航空

亲子要闻

萌娃的一句话逗得爸爸妈妈哈哈大笑,他说了什么?

艺术要闻

王羲之5000字行书真迹出土,全卷清晰如新,能多看一眼,都是福气

家居要闻

蓝调空舍 自由与个性

数码要闻

山灵推出MG200开放入耳式动圈耳机:首发价1398元

军事要闻

轰-6k在黄岩岛战备警巡示意图公布

无障碍浏览 进入关怀版