首页系统综合问题你应该了解的 5 种 TypeScript 设计模式

你应该了解的 5 种 TypeScript 设计模式

时间2022-12-17 11:31:50发布分享专员分类系统综合问题浏览228

今天小编给各位分享command的知识,文中也会对其通过你应该了解的 5 种 TypeScript 设计模式和TypeScript 系统入门到项目实战等多篇文章进行知识讲解,如果文章内容对您有帮助,别忘了关注本站,现在进入正文!

内容导航:

  • 你应该了解的 5 种 TypeScript 设计模式
  • TypeScript 系统入门到项目实战
  • TypeScript 和 JavaScript 的区别
  • 小白准备转行学习前端,有大神可以提一些建议吗
  • 一、你应该了解的 5 种 TypeScript 设计模式

    本文最初发布于 Medium 网站,经原作者授权由 InfoQ 中文站翻译并分享。

    设计模式是解决问题的良好模板,开发人员可以在自己的项目应用这些模式处理需求。现实中应付各种需求的模式数不胜数,一篇文章无法尽述。不过它们可以大致分为三个类别:

    结构模式,负责处理不同组件(或类)之间的关系,并形成新结构以提供新功能。结构模式的例子有组合(Composite)、适配器(Adapter)和装饰器(Decorator)。行为模式,它们能将组件之间的通用行为抽象为一个单独的实体,进而与你的创建模式结合起来。行为模式的例子包括命令(Command)、策略(Strategy)以及我个人最喜欢的一种:观察者(Observer)模式。创建模式,它们专注于类的实例化,简化新实体的创建过程,例如工厂(Factory)方法、单例(Singleton)和抽象工厂(Abstract Factory)。

    虽然它们可以直接在 JavaScript 中实现,特别是有了 ES6 后实现起来更容易了,但 TypeScript 采用的 OOP 方法使得开发人员可以简单明了地遵循通用指南(甚至来自其他 OOP 语言),从而获得这些模式的所有好处(而标准 JS 相比之下多少存在一些限制)。

    单例

    单例模式可能是最著名的设计模式之一。这是一种创建模式,它可以确保无论你多少次实例化一个类,你都只会有一个实例。

    这是处理数据库连接之类场景的好方法,因为你可能希望一次只处理一个连接,而不必在每次用户请求时都重新连接。

    //Simulate a database connectino classclass MyDBConn{    protected static instance: MyDBConn | null = null    private id: number = 0    constructor() {        //... db connection logic        this.id = Math.random() //the ID could represent the actual connection to the db    }        public getID(): number {        return this.id    }    public static getInstance(): MyDBConn {        if(!MyDBConn.instance) {            MyDBConn.instance = new MyDBConn()        }        return MyDBConn.instance    }}const connections = [                        MyDBConn.getInstance(),                        MyDBConn.getInstance(),                        MyDBConn.getInstance(),                        MyDBConn.getInstance(),                        MyDBConn.getInstance()                ]connections.forEach( c => {    console.log(c.getID())

    现在你不能直接实例化这个类,但使用 getInstance 方法时,你可以确保不会有多个实例。在上面的示例中,你可以看到包装数据库连接的伪类是怎样从这一模式中受益的。很容易将 id 属性视为实际连接,而这个小测试向你展示了,无论你调用 getInstance 方法多少次,“连接”总是相同的。代码的输出是:

    0.40470872509907130.40470872509907130.40470872509907130.40470872509907130.4047087250990713
    工厂方法

    如前所述,工厂方法像单例一样也是一种创建模式。但这种模式不是直接针对我们要创建的对象,而只管理它们的创建过程。

    解释一下:假设你要编写移动一些交通工具的代码,它们的类型有很大区别(例如汽车、自行车和飞机),移动代码应封装在每个交通工具类中,但调用这些 move 代码的方法可以是通用的。

    这里的问题是如何处理对象创建?你可能有一个具有 3 个方法的 creator 类,或者一个接收一个参数的方法。无论哪种情况,要扩展这种逻辑以支持创建更多交通工具,都需要你修改同一个类。

    但如果你决定使用工厂方法模式,则可以执行以下操作:

    现在,创建新对象所需的代码被封装到一个新类中,每种交通工具类型都对应一个。这样如果将来需要添加新类型,则只需添加一个新的类,不必修改任何现有的类。

    来看看我们如何使用 TypeScript 来实现这一点:

    interface Vehicle {    move(): void}//The classes we care about, the "move" method is where our "business logic" would liveclass Car implements Vehicle {    public move(): void {        console.log("Moving the car!")    }}class Bicycle implements Vehicle {    public move(): void {        console.log("Moving the bicycle!")    }}class Plane implements Vehicle {    public move(): void {        console.log("Flying the plane!")    }}//The VehicleHandler is "abstract" because noone is going to instantiate it//We want to extend it and implement the abstract methodabstract class VehicleHandler {    //This is the method real handlers need to implement    public abstract createVehicle(): Vehicle     //This is the method we care about, the rest of the business logic resides here    public moveVehicle(): void {        const myVehicle = this.createVehicle()        myVehicle.move()    }} //Here is where we implement the custom object creationclass PlaneHandler extends VehicleHandler{    public createVehicle(): Vehicle {        return new Plane()    }}class CarHandler  extends VehicleHandler{    public createVehicle(): Vehicle {        return new Car()    }}class BicycleHandler  extends VehicleHandler{    public createVehicle(): Vehicle {        return new Bicycle()    }}/// User code...const planes = new PlaneHandler()const cars = new CarHandler()planes.moveVehicle()cars.moveVehicle()

    本质上,我们最终关心的是自定义处理程序(handler)。之所以叫它们处理程序,是因为它们不仅负责创建对象,而且具有使用它们的逻辑(如 moveVehicle 方法所示)。这种模式的优点在于,如果要添加新的类型,你要做的就是添加其交通工具类和其处理程序类,而无需改动其他类的代码。

    观察者

    在所有模式中,我最喜欢的是观察者,这是因为我们可以用它来实现的行为类型。听说过 ReactJS 吗?它就是基于观察者模式的。前端 JavaScript 中的事件处理程序听过吗?也是基于它的,起码理论上是一致的。

    关键在于,通过观察者模式,你可以实现它们以及更多事物。

    本质上,这种模式表明你具有一组观察者对象,这些对象将对观察到的实体的状态变化做出反应。为了做到这一点,一旦观察端收到更改,就会调用一个方法来通知观察者。

    实践中这种模式相对容易实现,来看代码:

    type InternalState = {    event: String}abstract class Observer {     abstract update(state:InternalState): void } abstract class Observable {    protected observers: Observer[] = [] //the list of observers    protected state:InternalState = { event: "" } //the internal state observers are watching    public addObserver(o:Observer):void {        this.observers.push(o)    }        protected notify() {        this.observers.forEach( o => o.update(this.state) )    }}//Actual implementationsclass ConsoleLogger extends Observer  {    public update(newState: InternalState) {        console.log("New internal state update: ", newState)    }}class InputElement extends Observable {    public click():void {        this.state = { event: "click" }        this.notify()    }}const input = new InputElement()input.addObserver(new ConsoleLogger())input.click()

    如你所见,通过两个抽象类,我们可以定义 Observer,它代表对 Observable 实体上的更改做出反应的对象。在上面的示例中,我们假装有一个被点击的 InputElement 实体(类似于你在前端的 HTML 输入字段),以及一个 ConsoleLogger,用于自动记录 Console 发生的所有事情。这种模式的优点在于,它使我们能够了解 Observable 的内部状态并对其做出反应,而不必弄乱其内部代码。我们可以继续添加执行其他操作的 Observer,甚至包括对特定事件做出反应的观察者,然后让它们的代码决定对每个通知执行的操作。

    装饰器

    装饰器模式会在运行时向现有对象添加行为。从某种意义上说,你可以将其视为动态继承,因为即使你没有创建新类来添加行为,也会创建具有扩展功能的新对象。

    比如你有一个带有 move 方法的 Dog 类,现在你想扩展其行为,因为你想要一只超人狗(当你让它移动时它可以飞起来)和一只游泳狗(当你告诉它移动时就钻进水里)。

    一般来说,你会在 Dog 类中添加标准移动行为,然后以两种方式扩展该类,即 SuperDog 和 SwimmingDog 类。但是,如果你想将两者混合起来,则必须再创建一个新类来扩展它们的行为。其实这里有更好的方法。

    组合(Composition)使你可以将自定义行为封装在不同的类中,然后使用该模式将原始对象传递给它们的构造器来创建这些类的新实例。看一下代码:

    abstract class Animal {    abstract move(): void}abstract class SuperDecorator extends Animal {    protected comp: Animal        constructor(decoratedAnimal: Animal) {        super()        this.comp = decoratedAnimal    }        abstract move(): void}class Dog extends Animal {    public move():void {        console.log("Moving the dog...")    }}class SuperAnimal extends SuperDecorator {    public move():void {        console.log("Starts flying...")        this.comp.move()        console.log("Landing...")    }}class SwimmingAnimal extends SuperDecorator {    public move():void {        console.log("Jumps into the water...")        this.comp.move()    }}const dog = new Dog()console.log("--- Non-decorated attempt: ")dog.move()console.log("--- Flying decorator --- ")const superDog =  new SuperAnimal(dog)superDog.move()console.log("--- Now let's go swimming --- ")const swimmingDog =  new SwimmingAnimal(dog)swimmingDog.move()

    注意一些细节:

    实际上,SuperDecorator 类扩展了 Animal 类,Dog 类也扩展了这个类。这是因为装饰器需要提供与其尝试装饰的类相同的公共接口。SuperDecorator 类是 abstract,也就是说你实际上并没有使用它,只是用它来定义构造器,该构造器会将原始对象的副本保留在受保护的属性中。公共接口是在自定义装饰器内部完成覆盖的。SuperAnimal 和 SwimmingAnimal 是实际的装饰器,它们是添加额外行为的装饰器。

    这种设置的好处是,由于所有装饰器也间接扩展了 Animal 类,因此如果你要将两种行为混合在一起,则可以执行以下操作:

    console.log("--- Now let's go SUPER swimming --- ")const superSwimmingDog =  new SwimmingAnimal(superDog)superSwimmingDog.move()

    如果你要使用经典继承,则动态结果会多得多。

    组合

    最后来看组合模式,这是打包处理多个相似对象时非常有用且有趣的模式。

    这种模式使你可以将一组相似的组件作为一个组来处理,从而对它们执行特定的操作并汇总所有结果。

    这种模式的有趣之处在于,它不是一个简单的对象组,它可以包含很多实体或实体组,每个组可以同时包含更多组。这就是我们所说的树。

    看一个例子:

    interface IProduct {        getName(): string    getPrice(): number }//The "Component" entityclass Product implements IProduct {    private price:number     private name:string        constructor(name:string, price:number) {        this.name = name        this.price = price    }        public getPrice(): number {        return this.price    }        public getName(): string {        return this.name    }}//The "Composite" entity which will group all other composites and components (hence the "IProduct" interface)class Box implements IProduct {    private products: IProduct[] = []        contructor() {        this.products = []    }        public getName(): string {        return "A box with " + this.products.length + " products"    }         add(p: IProduct):void {        console.log("Adding a ", p.getName(), "to the box")        this.products.push(p)    }    getPrice(): number {        return this.products.reduce( (curr: number, b: IProduct) => (curr + b.getPrice()),  0)    }}//Using the code...const box1 = new Box()box1.add(new Product("Bubble gum", 0.5))box1.add(new Product("Samsung Note 20", 1005))const box2 = new Box()box2.add( new Product("Samsung TV 20in", 300))box2.add( new Product("Samsung TV 50in", 800))box1.add(box2)console.log("Total price: ", box1.getPrice())

    在上面的示例中,我们可以将 Product 放入 Box 中,也可以将 Box 放入其他 Box 中。这是组合的经典示例,因为你要达到的目的是获得要交付产品的完整价格,因此你要在大 Box 中添加每个元素的价格(包括每个较小 Box 的价格)。这样,通常称为“component”的元素是 Product 类,也称为树内的“leaf”元素。这是因为该实体没有子级。Box 类本身是组合类,具有子列表,所有子类都实现相同的接口。最后一部分代码是因为你希望能够遍历所有子项并执行相同的方法(请记住,这里的子项可以是另一个较小的组合)。

    该示例的输出应为:

    Adding a  Bubble gum to the boxAdding a  Samsung Note 20 to the boxAdding a  Samsung TV 20in to the boxAdding a  Samsung TV 50in to the boxAdding a  A box with 2 products to the boxTotal price:  2105.5

    因此,在处理遵循同一接口的多个对象时,请考虑使用这种模式。它将复杂性隐藏在单个实体(组合本身)中,你会发现它有助于简化与小组的互动。

    小结

    设计模式是用于解决问题的完美工具,但你必须先了解它们,并针对自身面对的场景做一些调整才能让它们起作用,或者修改你的业务逻辑以配合模式。无论是哪种方式,都是一项不错的投资。

    你最喜欢哪种模式呢?你会经常在项目中使用它们吗?在评论中分享自己的看法吧!

    原文链接: https://blog.bitsrc.io/design-patterns-in-typescript-e9f84de40449

    关注我并转发此篇文章,私信我“领取资料”,即可免费获得InfoQ价值4999元迷你书!

    一、TypeScript 系统入门到项目实战

    ### 课程介绍

    TS在构建大型应用上的优势,以及与JS的完美互通,让TS未来一片光明,从0到1系统学习,把TS真正应用到框架和项目中。

    在迷你“全栈”项目中学习TypeScript,以TypeScript完整串联前后端

    基础与实战“融合”,将知识讲解融于项目开发中,让你更快的掌握TS工程开发所必须的知识点

    ### 目录

    第1章 课程导学

    本章主要介绍课程的知识大纲,学习前提,讲授方式及预期收获。

    1-1 都2020了,还不抓紧学TypeScript?

    第2章 TypeScript 基础语法入门

    本章主要帮助大家理解 TypeScript 可以解决的问题和所带来的优势,帮助大家理解 TS 中的各种静态类型,包括:函数,数组,元组,类,抽象类接口等,迅速帮助大家理解 TS 的基础使用方式和语法。

    2-1 安装 VsCode 编辑器

    2-2 TypeScript的定义

    2-3 TypeScript带来了什么优势

    2-4 TypeScript基础环境搭建

    2-5 静态类型的深度理解

    2-6 基础类型和对象类型

    2-7 类型注解和类型推断

    2-8 函数相关类型

    2-9 基础语法复习

    2-10 数组和元组

    2-11 Interface接口

    2-12 类的定义与继承

    2-13 类中的访问类型和构造器

    2-14 静态属性,Setter和Getter

    2-15 抽象类

    2-16 作业节

    第3章 使用 TypeScript 编写爬虫工具

    本章将带大家使用 TypeScript 编写一个获取网站课程销量的爬虫工具,过程中对上一章节学习的 TypeScript 基础知识进行实践巩固,同时借助 TypeScript 中的 OOP 编程方式,给大家讲解部分面向对象开发中的设计模式。

    3-1 爬虫概述及正版密钥获取 (04:48)

    3-2 使用SuperAgent和类型定义文件获取页面内容 (18:43)

    3-3 使用cheerio进行数据提取 (12:32)

    3-4 爬取数据的结构设计和存储 (18:00)

    3-5 使用组合设计模式优化代码 (21:21)

    3-6 单例模式实战复习 (07:24)

    3-7 TypeScript的编译运转过程的进一步理解 (21:04)

    3-8 作业节

    第4章 TypeScript 语法进阶

    本章将给大家讲解更多的 TypeScript 进阶语法以及原理性知识。包括如何进行 TypeScript 编译过程的配置,联合类型,类型保护,枚举类型,泛型等知识点。同时也给大家扩展讲解了类型定义文件的使用及编写方式等内容。通过本章的学习,大家基本可以掌握 TypeScript 中绝大部分的语法知识点。

    4-1 TypeScript中的配置文件(上)

    4-2 TypeScript中的配置文件(下)

    4-3 作业节

    4-4 联合类型和类型保护

    4-5 Enum 枚举类型

    4-6 函数泛型

    4-7 类中的泛型以及泛型类型

    4-8 命名空间-namespace(上)

    4-9 命名空间-namespace(下)

    4-10 import对应的模块化-缺代码

    4-11 使用 Parcel 打包 TS 代码

    4-12 描述文件中的全局类型(上)

    4-13 描述文件中的全局类型(下)

    4-14 模块代码的类型描述文件

    4-15 作业节

    4-16 泛型中keyof语法的使用

    第5章 使用 Express 框架开发数据爬取及展示接口

    本章将在 Express 框架中使用 TypeScript 的语法进行登陆,数据爬取和展示接口的开发,过程中对之前的基础语法进行实践巩固,同时讲解以 JavaScript 作为开发语言的框架中使用 TypeScript 会遇到的问题以及解决方案。

    5-1 Express 基础项目结构搭建

    5-2 使用TS编写常规express代码遇到的问题

    5-3 扩展解决 Express 的类型定义文件问题

    5-4 登陆功能的开发

    5-5 统一接口数据结构,优化代码

    第6章 TypeScript 高级语法

    本章主要讲解 TypeScript 中,装饰器和元数据的语法知识,包括类装饰器,方法装饰器,属性装饰器和参数装饰器在本章中都会详细讲解,通过本章的学习,大家基本上完成了对 TypeScript 所有重点语法的学习。

    6-1 类的装饰器(1)

    6-2 类的装饰器(2)

    6-3 方法装饰器

    6-4 访问器的装饰器

    6-5 属性的装饰器

    6-6 参数装饰器

    6-7 装饰器实际使用的小例子

    6-8 reflect-metadata

    6-9 装饰器的执行顺序

    6-10 作业节

    第7章 Express 项目代码改良

    结合上一章学习的装饰器和元数据的语法知识,本章将通过面向对象的方式,对之前的接口代码进行全面重构,最终帮大家编写出和当前主流 Node 框架风格一致的后端应用代码,对上一章的知识点进行实战巩固,同时帮助大家理解 Node 框架设计背后的原理性知识。

    7-1 创建控制器和装饰器

    7-2 通过装饰器实现项目路由功能

    7-3 多种请求方法装饰器的生成

    7-4 .中间件装饰器的编写

    7-5 .代码结构优化

    7-6 .练习题:如何在一个方法上使用多个装饰器

    第8章 使用 React 编写爬取数据的展示页面

    本章将带大家使用TS的语法进行前端 React 代码的开发,过程中会给大家讲解在 React 和 Redux 等前端核心框架上如何正确巧妙的使用TypeScript。本章的最后,我们将产出一个完整的爬虫项目,并通过可视化的方式,对爬取到的数据进行展示。

    8-1 初始化 React 项目

    8-2 编写登陆表单

    8-3 类型及路由的使用

    8-4 前后端代码联调及登陆跳转逻辑开发

    8-5 登陆退出功能完整优化

    8-6 数据爬取功能打通及 Echarts 的使用

    8-7 折线图数据处理及展示

    8-8 接口数据类型的冗余定义问题

    8-9 通过 Typescript 简化前后端协作模式

    第9章 课程总结

    本章将对整个项目所学习到的知识点进行总结,并给出大家进一步深入学习 TS 的方法和技巧。

    9-1 课程总结及后续学习方法推荐

    ### 获取方式:TypeScript 系统入门到项目实战

    二、TypeScript 和 JavaScript 的区别

    TypeScript 和 JavaScript 是目前项目开发中较为流行的两种脚本语言,我们已经熟知 TypeScript 是 JavaScript 的一个超集。JavaScript 和 TypeScript 的主要差异:

    1、TypeScript 可以使用 JavaScript 中的所有代码和编码概念,TypeScript 是为了使 JavaScript 的开发变得更加容易而创建的。例如,TypeScript 使用类型和接口等概念来描述正在使用的数据,这使开发人员能够快速检测错误并调试应用程序

    2、TypeScript 从核心语言方面和类概念的模塑方面对 JavaScript 对象模型进行扩展。

    3、JavaScript 代码可以在无需任何修改的情况下与 TypeScript 一同工作,同时可以使用编译器将 TypeScript 代码转换为 JavaScript。

    4、TypeScript 通过类型注解提供编译时的静态类型检查。

    5、TypeScript 中的数据要求带有明确的类型,JavaScript不要求。

    6、TypeScript 为函数提供了缺省参数值。

    7、TypeScript 引入了 JavaScript 中没有的“类”概念。

    8、TypeScript 中引入了模块的概念,可以把声明、数据、函数和类封装在模块中。

    三、小白准备转行学习前端,有大神可以提一些建议吗

    学习是以兴趣为前提的,你要对你所要学的内容产生兴趣,这样你才会花心思去学习。这和是不是小白没关系的,对于小白而言,在学习过程中就需要更努力,多花时间和心思没有什么是学不会的。

    自学方法:

    1、作为一个初学者,你必须明确系统的学习方案,我建议一定有一个指导的人,全靠自己学,放弃的几率非常大,在你对于web前端还没有任何概念的时候,需要一个人领进门,之后就都靠自己钻研,第一步就是确定web前端都需要哪些内容,并且在多少时间内学完,建议时间6个月保底。

    2、视频为主,书为辅。很多初学者在学习前端的时候非常喜欢去买书,但是最后的结果是什么?看来看去什么都不会写,所以在这里给大家提醒,书可以看,但是是在建立于你已经对于某个知识点有了具体操作的执行后,在用书去巩固概念,这样更加利于你对于知识的理解。

    3、对于学习技术来讲,掌握一个学习方法是非常重要的,其实对于学习web前端来讲,学习方法确实很多都是相通的,一旦学习方法不对,可能就会造成“方法不对,努力白费”。其实关于这方面还是很多的,我就简单说个例子,有的人边听课边跟着敲代码,这样就不对,听课的时候就专心听,做题的时候就专心做题,这都是过来人的经验,一定要听。根据每个人的不同,可能学习方法也会有所出路,找到适合你自己的学习法方法是学习的前提。

    4、不建议自己一个人瞎学,在我了解学习编程的这些人来看,从零基础开始学并且最后成功做这份工作的其实并没有几个,我觉得大部分原因就是因为他们都不了解web前端是干什么的,学什么的,就盲目的买书看,到处找视频看,最后看着看着就放弃了,所以我建议初学者在没有具体概念之前,还是找有经验的人请教一下,聊过之后你就会知道web前端具体是干什么的,该怎么学,这是我个人的小建议,可以不采纳。

    自学路线:

    第1阶段:前端页面重构(4周)

    内容包含了:(PC端网站布局项目、HTML5+CSS3基础项目、WebApp页面布局项目)

    第2阶段:JavaScript高级程序设计(5周)

    内容包含:(原生JavaScript交互功能开发项目、面向对象进阶与ES5/ES6应用项目、JavaScript工具库自主研发项目)

    第3阶段:PC端全栈项目开发(3周)

    内容包含:(jQuery经典交互特效开发、HTTP协议、Ajax进阶与PHP/JAVA开发项目、前端工程化与模块化应用项目、PC端网站开发项目、PC端管理信息系统前端开发项目)

    第4阶段:移动端项目开发(6周)

    内容包含:(Touch端项目、微信场景项目、应用Angular+Ionic开发WebApp项目、应用Vue.js开发WebApp项目、应用React.js开发WebApp项目)

    第5阶段:混合(Hybrid,ReactNative)开发(1周)

    内容包含:(微信小程序开发、ReactNative、各类混合应用开发)

    第6阶段:NodeJS全栈开发(1周)

    内容包括:(WebApp后端系统开发、一、NodeJS基础与NodeJS核心模块二、Express三、noSQL数据库)

    视频教程:

    如果你对于学习前端有任何不懂的可以随时来问我,如果没有比较好的教程,也可以问我要。

    关于command的问题,通过《TypeScript 和 JavaScript 的区别》、《小白准备转行学习前端,有大神可以提一些建议吗》等文章的解答希望已经帮助到您了!如您想了解更多关于command的相关信息,请到本站进行查找!

    爱资源吧版权声明:以上文中内容来自网络,如有侵权请联系删除,谢谢。

    command
    (国际)朝鲜称成功进行大功率固体燃料发动机试验 我国教育资源短缺,“内卷化”严重,让学生的努力变得毫无价值