感觉越学越糊涂了 啊!?好不容易搞清楚了类是什么,又来学接口。乍一看:差不多啊!

接口(interface)

 

接口主要用于定义对象的类型结构,就像是给对象制定了一个“模板”,规定了对象必须具备哪些属性和方法。

interface关键字

interface关键字用来定义接口。

以下是一个简单的示例:

// 定义一个描述人的接口
interface Person {
    name: string;
    age: number;
    sayHello: () => void;
}

person接口规定了一个对象必须包含  name(字符串类型)、age(数字类型)属性,以及一个sayhello的方法,该方法不接受参数,并没有返回值。

接口的实现

// 定义一个描述人的接口
interface Person {
    name: string;
    age: number;
    sayHello: () => void;
}

// 创建一个实现 Person 接口的对象
const person: Person = {
    name: 'Alice',
    age: 25,
    sayHello: function() {
        console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
    }
};

// 调用 sayHello 方法
person.sayHello(); 

在上述代码中,用person对象实现了person接口,它包含了接口所规定的  name、age、属性和  sayhello  方法。然后调用了sayhello方法,输出相应信息。

接口属性

可选属性(?)

因为在接口中,有一些属性可能是不必要的,这是可以使用可选属性。

在属性后面加一个    ?  来表示可选属性。

interface Book {
    title: string;
    author?: string; // 可选属性
}

const myBook: Book = {
    title: 'The Great Gatsby'
};

只读属性(readonly)

如果一个属性在对象创建后不允许被修改,可以使用只读属性 ,在属性名前加  readonly  关键字。

interface Point {
    readonly x: number;
    readonly y: number;
}

const p: Point = { x: 10, y: 20 };
// p.x = 30; // 这行代码会报错,因为 x 是只读属性

接口继承(extends)

接口可以继承其它接口,从而实现扩展或修改原有的接口定义。

// 定义一个基本形状接口
interface Shape {
    color: string;
}

// 定义一个圆形接口,继承自 Shape 接口
interface Circle extends Shape {
    radius: number;
}

const myCircle: Circle = {
    color: 'red',
    radius: 5
};

Circle接口继承了Shape接口的color属性,并添加了自己的radius属性。

函数类型接口

// 定义一个函数类型接口
interface AddFunction {
    (a: number, b: number): number;
}

// 实现 AddFunction 接口的函数
const add: AddFunction = function(a, b) {
    return a + b;
};

console.log(add(3, 5)); 

在上述代码中,AddFunction 接口描述了一个接受两个数字参数并返回一个数字的函数类型,add 函数实现了这个接口

 接口和类的不同

 

定义和用途

接口

  • 定义:接口是一种抽象的类型定义,它主要用于描述对象的结构,规定了对象必须具备哪些属性和方法,但并不包含这些属性和方法的具体实现。
  • 用途:接口通常用于定义代码的契约,让不同的对象遵循相同的规范,提高代码的可维护性和可扩展性。比如在一个应用中,多个不同的组件可能需要实现相同的交互逻辑,就可以通过接口来统一规范

定义一个接口:

// 定义一个接口
interface Animal {
    name: string;
    speak(): void;
}

  • 定义:类是一种具体的类型,它不仅可以定义对象的属性和方法,还可以包含这些属性和方法的具体实现。类是对象的蓝图,通过类可以创建出具体的对象实例。
  • 用途:类用于创建具有相同属性和行为的对象集合,封装数据和行为,实现代码的复用。例如,在开发一个游戏时,可以定义一个 Player 类来表示游戏中的玩家
// 定义一个类
class Dog {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    speak() {
        console.log(`${this.name} says Woof!`);
    }
}

实例化

接口

接口本身不能被实例化,它只是一种类型约束,不能直接创建对象。接口主要用于类型检查,确保对象符合接口定义的结构。

interface Animal {
    name: string;
    speak(): void;
}

// 以下代码会报错,因为接口不能实例化
// const myAnimal = new Animal(); 

类可以被实例化,通过 new 关键字可以创建类的对象实例。实例化后的对象具有类所定义的属性和方法。

class Dog {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    speak() {
        console.log(`${this.name} says Woof!`);
    }
}

// 实例化 Dog 类
const myDog = new Dog('Buddy');
myDog.speak(); 

继承和实现

接口

接口可以继承其他接口,通过 extends 关键字实现接口的扩展,一个接口可以继承多个接口,从而组合多个接口的属性和方法。此外,类可以实现接口,确保类的实例满足接口定义的规范。

// 定义一个基础接口
interface Shape {
    color: string;
}

// 定义一个继承自 Shape 的接口
interface Circle extends Shape {
    radius: number;
}

// 类实现接口
class MyCircle implements Circle {
    color: string;
    radius: number;
    constructor(color: string, radius: number) {
        this.color = color;
        this.radius = radius;
    }
}

类可以通过 extends 关键字继承另一个类,子类会继承父类的属性和方法,并且可以对其进行重写或扩展。但类只能单继承,即一个类只能有一个直接父类。

// 定义一个父类
class Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    speak() {
        console.log(`${this.name} makes a sound.`);
    }
}

// 定义一个子类,继承自 Animal 类
class Cat extends Animal {
    speak() {
        console.log(`${this.name} says Meow!`);
    }
}

访问修饰符的使用

接口中不能使用访问修饰符,(如 privateprotectedpublic)。

类中可以。

抽象类和接口

抽象类与接口都无法实例化。抽象类是类的抽象,抽象类用来捕捉子类的通用特性,接口是行为的抽象。

接口的特点

  • 只定义规范:接口只包含方法和属性的签名,不包含具体的实现。
  • 多实现:一个类可以实现多个接口,从而实现多重继承的效果。
  • 类型检查:接口可以用于类型检查,确保对象具有特定的属性和方法
// 定义接口
interface Person {
  name: string;
  age: number;
  sayHello(): void;
}

// 实现接口
class Student implements Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
  }
}

// 使用实现了接口的类
const student = new Student('Alice', 20);
student.sayHello(); 

 interface Person:定义了一个名为Person的接口,包含nameage两个属性,以及一个sayHello方法。

class Student implements PersonStudent类实现了Person接口,因此必须实现接口中定义的所有属性和方法。

student.sayHello():调用Student类的sayHello方法。

 

抽象类(Abstract Class)的特点

  • 不能实例化:抽象类不能直接创建实例,只能通过子类来创建。
  • 包含抽象方法:抽象类可以包含抽象方法,这些方法必须在子类中实现。
  • 提供公共实现:抽象类可以包含具体方法,这些方法可以直接在子类中使用。
// 定义抽象类
abstract class Animal {
  constructor(protected name: string) {}

  // 抽象方法
  abstract makeSound(): void;

  // 具体方法
  move(distance: number = 0) {
    console.log(`${this.name} moved ${distance}m.`);
  }
}

// 继承抽象类
class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }

  // 实现抽象方法
  makeSound() {
    console.log(`${this.name} barks.`);
  }
}

// 使用继承了抽象类的子类
const dog = new Dog('Buddy');
dog.makeSound(); 
dog.move(10); 

 abstract class Animal定义了一个名为Animal抽象类,包含一个构造函数、一个抽象方法makeSound和一个具体方法move。

class Dog extends Animal。Dog类继承了Animal抽象类,必须实现抽象方法makeSound。

 dog.makeSound和dog.move。分别调用Dog类的makeSound方法和继承自Animal类的move方法。

对比

  • 实例化:接口不能实例化,抽象类也不能实例化,但可以通过子类实例化。
  • 实现方式:一个类可以实现多个接口,但只能继承一个抽象类。
  • 方法实现:接口中的方法都是抽象的,没有具体实现;抽象类中可以包含抽象方法和具体方法。
  • 使用场景:接口主要用于定义规范,实现多态性;抽象类主要用于提取公共代码,提供公共实现。

 

 

 

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐