编程与类型系统08
发表于:2024-07-03 | 分类: 学习

面向对象编程的元素

面向对象编程(Object-Oriented Programming,OOP):OOP 是基于对象的概念的一种编程范式,对象可以包含数据和代码。数据是对象的状态,代码是一个或多个方法,也叫作“消息”。在面向对象系统中,通过使用其他对象的方法,对象之间可以“对话”或者发送消息。

  • 接口或契约:接口(或契约)描述了实现该接口的任何对象都理解的一组消息。消息是方法,包括名称、实参和返回类型。接口没有任何状态。与现实世界的契约(它们是书面协议)一样,接口也相当于书面协议,规定了实现者将提供什么。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    interface ILogger {
    log(line: string): void;
    }

    class SLogger implements ILogger {
    log(line: string): void {
    console.log(line);
    }
    }
  • 继承和“是一个”关系:继承会在子类型与父类型之间建立“是一个”关系。如果基类是Shape,派生类是Circle,关系就是“Circle是一个Shape”。这是继承在语义上的含义,可用来判断是否应该在两个类型之间应用继承。

    抽象类和“普通”类,或者说具体类的唯一区别在于,我们不能直接创建抽象类的实例。
    通常,让子类是具体类,让层次结构上方的父类是抽象类,这是一个好主意。这种技术使得跟踪信息和避免意外行为变得更加简单。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    interface Radius {
    radius(): number;
    }
    abstract class Shape implements Radius {
    readonly x: number;
    readonly y: number;
    constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
    }
    abstract radius(): number;
    }
    class Circles extends Shape {
    radius(): number {
    return this.x * this.y;
    }
    }

  • 组合和“有一个”关系:组合在容器类型和被包含类型之间建立了一种“有一个”关系。如果类型是Circle,被包含的类是Point,那么它们的关系是“Circle有一个Point”(该Point定义了Circle的圆心)。这是组合在语义上的意义,可用于判断是否应该在两个类型之间使用组合。

    当我们把一个值类型的实例赋值给一个变量,或者将其作为实参传递给一个函数时,在内存中会复制其内容,实际上创建了另外一个实例。另一方面,当我们赋值一个引用类型的实例时,并不会复制其完整的状态,而只是复制其引用。原变量和新变量将指向相同的对象,并能够修改其状态。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class Shape {
    id: string;
    constructor(id: string) {
    this.id = id;
    }
    }

    class Point {
    x: number;
    y: number;
    constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
    }
    }

    class Circle extends Shape {
    center: Point;
    radius: number;
    constructor(id: string, center: Point, radius: number) {
    super(id);
    this.radius = radius;
    this.center = center;
    }
    }
  • 混入和包含关系:混入在一个类型与其混入类型之间建立了“包含”关系。如果类是 Cat,混入类是HunterBehavior,那么二者的关系是“Cat包含HunterBehavior”。这是混入在语义上的含义,与继承的“是一个”关系不同(如图 8.8 所示)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function extend<First, Second>(first: First, second: Second): First & Second {
    const result: unknown = {};
    for (const prop in first) {
    if (first.hasOwnProperty(prop)) {
    (<First>result)[prop] = first[prop];
    }
    }
    for (const prop in second) {
    if (second.hasOwnProperty(prop)) {
    (<Second>result)[prop] = second[prop];
    }
    }
    return result;
    }
    class MeowIngPet implements Pet {
    meow(): void {}
    }
    class HuntBehavior {
    track(): void {}
    stalk(): void {}
    pounce(): void {}
    }
    type Cat = MeowIngPet & HuntBehavior;
    const fluffy: Cat = extend(new MeowIngPet(), new HuntBehavior());

上一篇:
编程与类型系统09
下一篇:
编程与类型系统07