当前位置: 首页 > news >正文

Day 11 - Interface 与类型契约

目标:掌握ArkTS接口的定义、实现、继承,理解接口与抽象类的区别
预计时间:1.5-2小时


课前思考

回顾Day 10我们学习的抽象类:

abstract class Animal {abstract name: string;abstract makeSound(): void;move(): void {console.log("动物在移动");}
}

思考一个问题:

在C++中,一个类可以同时继承多个基类(多重继承)。但ArkTS的类只能extends一个父类。
如果需要让SmartPhone同时具有Camera的能力、GPS的能力、MusicPlayer的能力,该怎么办?

这就引出了今天的主题——Interface(接口)


第一部分:Interface 基础(对标 C++ 纯虚基类)

1.1 为什么需要接口 —— 抽象类的局限性

抽象类的局限:

// 假设我们有多个能力维度
abstract class Camera {abstract takePhoto(): void;
}abstract class GPS {abstract getLocation(): string;
}// ❌ 错误:ArkTS类只能继承一个父类
// class SmartPhone extends Camera, GPS {}  // 语法错误!

对比C++:

// C++支持多重继承(但有菱形继承问题)
class SmartPhone : public Camera, public GPS {// ...
};

接口解决方案:

// 定义接口(纯契约,无实现)
interface Camera {takePhoto(): void;
}interface GPS {getLocation(): string;
}interface MusicPlayer {playMusic(song: string): void;
}// ✅ 类可以实现多个接口
class SmartPhone implements Camera, GPS, MusicPlayer {takePhoto(): void {console.log("拍照:咔嚓!");}getLocation(): string {return "GPS坐标:39.9, 116.4";}playMusic(song: string): void {console.log(`正在播放:${song}`);}
}

核心区别:

特性 C++纯虚基类 ArkTS接口
定义 class + 纯虚函数 interface 关键字
多继承 支持但有风险 类可多实现接口,安全
实现 可包含成员变量和具体方法 只能声明属性和方法签名
构造函数 可以有 不能有

注意:Interface 是结构契约(Structure Contract),不是简单的"类型契约"。它要求实现类必须具有完全匹配的结构(属性名、类型、可选性完全一致)。


1.2 interface 定义语法

基本语法:

// 定义接口
interface Person {// 属性声明(只有类型,没有初始值)name: string;age: number;// 方法签名(无实现,没有 { ... } 代码块)sayHello(): void;getInfo(): string;
}// 实际用法:类实现接口
class Student implements Person {name: string;age: number;constructor(name: string, age: number) {this.name = name;this.age = age;}sayHello(): void {console.log(`你好,我是${this.name}`);}getInfo(): string {return `${this.name}, ${this.age}岁`;}
}

对比C++纯虚基类:

class IPerson {
public:std::string name;int age;virtual void sayHello() = 0;virtual std::string getInfo() = 0;virtual ~IPerson() = default;
};// 实现类必须继承
class PersonImpl : public IPerson {
public:void sayHello() override {std::cout << "你好,我是" << name << std::endl;}std::string getInfo() override {return name + ", " + std::to_string(age) + "岁";}
};

关键差异:

  • C++纯虚基类可以包含成员变量,ArkTS接口只能声明属性类型
  • C++需要虚析构函数,ArkTS接口无此概念
  • ArkTS接口更轻量,纯粹是类型契约

1.3 可选属性

使用 ? 标记可选属性:

interface Product {id: number;name: string;price: number;description?: string;      // 可选属性discountPrice?: number;    // 可选属性
}// 可以不带可选属性
let product1: Product = {id: 1001,name: "手机",price: 2999
};// 也可以带可选属性
let product2: Product = {id: 1002,name: "笔记本",price: 5999,description: "高性能轻薄本",discountPrice: 5499
};

对比C++:

// C++没有直接的可选属性语法,通常用默认值或std::optional(C++17)
class Product {
public:int id;std::string name;double price;std::optional<std::string> description;  // C++17std::optional<double> discountPrice;
};

ArkTS特点:

  • ? 语法简洁直观
  • 编译器会检查可选属性的存在性

1.4 函数类型属性

接口中可以声明函数类型的属性:

interface Calculator {// 普通属性model: string;// 函数类型属性add: (a: number, b: number) => number;subtract: (a: number, b: number) => number;// 可选的函数类型属性multiply?: (a: number, b: number) => number;
}// 实现
let simpleCalc: Calculator = {model: "基础版",add: (a: number, b: number): number => a + b,subtract: (a: number, b: number): number => a - b// multiply 可选,可以不提供
};let advancedCalc: Calculator = {model: "高级版",add: (a: number, b: number): number => a + b,subtract: (a: number, b: number): number => a - b,multiply: (a: number, b: number): number => a * b
};

对比C++:

// C++使用std::function或函数指针
class Calculator {
public:std::string model;std::function<int(int, int)> add;std::function<int(int, int)> subtract;std::function<int(int, int)> multiply;  // 可空
};

第二部分:Class 实现 Interface

2.1 implements 语法

类使用 implements 关键字实现接口:

interface Drawable {draw(): void;
}interface Resizable {resize(width: number, height: number): void;
}// 类实现单个接口
class Circle implements Drawable {private radius: number;constructor(radius: number) {this.radius = radius;}// 必须实现接口方法draw(): void {console.log(`绘制圆形,半径:${this.radius}`);}
}// 类实现多个接口
class Rectangle implements Drawable, Resizable {private width: number;private height: number;constructor(width: number, height: number) {this.width = width;this.height = height;}draw(): void {console.log(`绘制矩形:${this.width} x ${this.height}`);}resize(width: number, height: number): void {this.width = width;this.height = height;console.log(`调整大小为:${width} x ${height}`);}
}

实现规则:

  1. 类必须实现接口中所有非可选属性和方法
  2. 方法的参数类型和返回类型必须匹配
  3. 类可以有额外的属性和方法

2.2 实现多个接口

对标C++多重继承纯虚基类:

interface Flyable {fly(): void;maxAltitude: number;
}interface Swimmable {swim(): void;maxDepth: number;
}interface Walkable {walk(): void;speed: number;
}// 类实现多个接口(类似C++多重继承多个纯虚基类)
class Duck implements Flyable, Swimmable, Walkable {maxAltitude: number = 1000;maxDepth: number = 5;speed: number = 10;fly(): void {console.log("鸭子飞翔,最高" + String(this.maxAltitude) + "米");}swim(): void {console.log("鸭子游泳,最深" + String(this.maxDepth) + "米");}walk(): void {console.log("鸭子走路,速度" + String(this.speed) + "km/h");}
}

对比C++:

class IFlyable {
public:int maxAltitude;virtual void fly() = 0;virtual ~IFlyable() = default;
};class ISwimmable {
public:int maxDepth;virtual void swim() = 0;virtual ~ISwimmable() = default;
};class IWalkable {
public:int speed;virtual void walk() = 0;virtual ~IWalkable() = default;
};// C++多重继承(注意:可能有菱形继承问题)
class Duck : public IFlyable, public ISwimmable, public IWalkable {
public:Duck() {maxAltitude = 1000;maxDepth = 5;speed = 10;}void fly() override { /* ... */ }void swim() override { /* ... */ }void walk() override { /* ... */ }
};

ArkTS优势:

  • 没有菱形继承问题(接口无实现,无状态)
  • 编译器强制检查所有接口的实现
  • 更清晰、更安全的契约机制

2.3 实现多个接口时的成员合并规则

当类实现多个接口时,如果多个接口有同名成员(属性或方法),必须满足类型兼容,合并后取最严格的要求。

属性合并

情况1:同名同类型,都必需

interface A { value: number; }      // 必需
interface B { value: number; }      // 必需// ✅ 编译通过,合并后为必需
class C implements A, B {value: number = 0;  // 必需
}

情况2:同名同类型,都可选

interface A { value?: number; }      // 可选
interface B { value?: number; }      // 可选// ✅ 编译通过,合并后为可选
class C implements A, B {value?: number = 0;  // 可选(或必需也可以)
}

情况3:同名同类型,一个必需一个可选

interface A { value: number; }       // 必需
interface B { value?: number; }      // 可选// ✅ 编译通过,合并后为必需(取最严格)
class C implements A, B {value: number = 0;  // 必需,同时满足两者
}

情况4:同名不同类型

interface A { value: number; }       // number
interface B { value: string; }       // string// ❌ 编译错误:value类型不兼容(number vs string)
// class C implements A, B {}

方法合并

方法的合并规则与属性相同:同名方法的参数类型返回类型必须完全一致。

interface A {process(data: string): number;   // 参数 string,返回 number
}interface B {process(data: string): number;   // 必须完全一致
}// ✅ 编译通过
class C implements A, B {process(data: string): number {return data.length;}
}

方法签名不一致会报错:

interface A {process(data: string): number;
}interface B {process(data: number): string;   // ❌ 参数和返回类型都不同
}// ❌ 编译错误:方法签名不兼容
// class C implements A, B {}

可选方法

接口中的方法也可以是可选的:

interface A {requiredMethod(): void;          // 必需方法optionalMethod?(): void;         // 可选方法(带 ?)
}class B implements A {requiredMethod(): void {console.log("必须实现");}// optionalMethod 可以不实现
}

合并原则:

  • 类型(属性类型 / 方法签名):必须完全相同
  • 可选性:任一必需 → 合并后必需;全部可选 → 合并后可选

2.4 同时继承和实现

类可以 extends 一个父类,同时 implements 多个接口:

// 基类
class Animal {name: string;constructor(name: string) {this.name = name;}eat(): void {console.log(`${this.name} 在吃东西`);}
}// 接口定义额外能力
interface Flyable {fly(): void;
}interface EggLayer {layEggs(): void;
}// 类继承Animal,同时实现多个接口
class Bird extends Animal implements Flyable, EggLayer {wingSpan: number;constructor(name: string, wingSpan: number) {super(name);this.wingSpan = wingSpan;}// 实现Flyable接口fly(): void {console.log(`${this.name} 展翅飞翔,翼展${this.wingSpan}米`);}// 实现EggLayer接口layEggs(): void {console.log(`${this.name} 在下蛋`);}// Bird特有的方法chirp(): void {console.log(`${this.name}:叽叽叽`);}
}// 使用
let sparrow = new Bird("麻雀", 0.25);
sparrow.eat();      // 继承自Animal
sparrow.fly();      // 实现自Flyable
sparrow.layEggs();  // 实现自EggLayer
sparrow.chirp();    // Bird特有

对比C++:

class Animal {
public:std::string name;Animal(const std::string& name) : name(name) {}virtual void eat() { /* ... */ }
};class IFlyable {
public:virtual void fly() = 0;virtual ~IFlyable() = default;
};class IEggLayer {
public:virtual void layEggs() = 0;virtual ~IEggLayer() = default;
};// C++:继承一个类,实现多个纯虚基类
class Bird : public Animal, public IFlyable, public IEggLayer {
public:double wingSpan;Bird(const std::string& name, double wingSpan) : Animal(name), wingSpan(wingSpan) {}void fly() override { /* ... */ }void layEggs() override { /* ... */ }
};

语法顺序: 必须先 extendsimplements

// ✅ 正确
class MyClass extends Base implements A, B {}// ❌ 错误
// class MyClass implements A, B extends Base {}

第三部分:Interface 继承

3.1 接口继承接口

接口可以使用 extends 继承其他接口:

// 基础接口
interface Shape {color: string;draw(): void;
}// 接口继承接口
interface Circle extends Shape {radius: number;getArea(): number;
}// Circle 包含:color, radius, draw(), getArea()
let myCircle: Circle = {color: "red",radius: 10,draw(): void {console.log(`绘制${this.color}圆形`);},getArea(): number {return 3.14 * this.radius * this.radius;}
};

对比C++:

// C++接口继承也是用public继承
class IShape {
public:std::string color;virtual void draw() = 0;virtual ~IShape() = default;
};class ICircle : public IShape {
public:double radius;virtual double getArea() = 0;
};

3.2 接口的多重继承

接口可以多继承(类不行):

interface HasName {name: string;
}interface HasId {id: number;
}interface HasTimestamp {createdAt: number;updatedAt: number;
}// 接口继承多个接口(这是允许的!)
interface Entity extends HasName, HasId, HasTimestamp {isActive: boolean;
}// Entity 现在包含所有属性
let user: Entity = {name: "张三",id: 1001,createdAt: Date.now(),updatedAt: Date.now(),isActive: true
};

为什么接口可以多继承?

  • 接口只有类型声明,没有实现
  • 没有状态(成员变量初始化值)
  • 不存在菱形继承的歧义问题


第四部分:Abstract Class vs Interface

4.1 能力对比表

特性 Abstract Class Interface
构造函数 可以有 不能有
具体方法 可以有(带实现) 不能有(纯签名)
具体属性 可以有(带初始值) 只能声明类型
抽象方法 可以有 所有方法都是抽象的
访问修饰符 支持 public/private/protected 不能写修饰符,但实现类中对应成员必须是 public
状态保持 可以维护状态 无状态
多继承 类只能继承一个 接口可以多继承/多实现
实例化 不能直接实例化 不能直接实例化

4.2 如何选择

决策口诀: "有实现用abstract,纯契约用interface"

使用 Abstract Class 的场景:

// 有共享实现,需要复用代码
abstract class DataSource {protected cache: Map<string, object> = new Map();// 具体方法:共享实现protected getFromCache(key: string): object | undefined {return this.cache.get(key);}protected addToCache(key: string, value: object): void {this.cache.set(key, value);}// 抽象方法:子类必须实现abstract connect(): void;abstract fetchData(query: string): object[];
}class DatabaseSource extends DataSource {connect(): void {// 实现数据库连接console.log("连接数据库");}fetchData(query: string): object[] {// 使用父类的缓存机制let cached = this.getFromCache(query);if (cached !== undefined) {return cached as object[];}let result: object[] = []; // 从数据库获取this.addToCache(query, result);return result;}
}

使用 Interface 的场景:

// 纯契约定义,跨类族的能力规范
interface Persistable {toJSON(): string;fromJSON(json: string): void;
}interface Validatable {validate(): boolean;getErrors(): string[];
}interface Serializable {serialize(): Uint8Array;
}// 不同类族的类可以实现相同接口
class User implements Persistable, Validatable {// User的实现...toJSON(): string { return ""; }fromJSON(json: string): void {}validate(): boolean { return true; }getErrors(): string[] { return []; }
}class Product implements Persistable, Validatable, Serializable {// Product的实现...toJSON(): string { return ""; }fromJSON(json: string): void {}validate(): boolean { return true; }getErrors(): string[] { return []; }serialize(): Uint8Array { return new Uint8Array(); }
}

4.3 实际场景演示

场景:设计一个插件系统

// 插件基础类:提供通用功能
abstract class Plugin {readonly name: string;readonly version: string;private isEnabled: boolean = false;constructor(name: string, version: string) {this.name = name;this.version = version;}// 模板方法:定义初始化流程initialize(): void {console.log(`初始化插件:${this.name} v${this.version}`);this.onInitialize();this.isEnabled = true;}destroy(): void {console.log(`销毁插件:${this.name}`);this.onDestroy();this.isEnabled = false;}// 抽象方法:子类必须实现abstract onInitialize(): void;abstract onDestroy(): void;// 具体方法getStatus(): string {return this.isEnabled ? "运行中" : "已停止";}
}// 接口定义特定能力
interface DataProcessor {processData(input: object): object;supportsFormat(format: string): boolean;
}interface UIComponent {render(): void;getUIConfig(): object;
}// 具体插件:继承Plugin基类,实现特定接口
class CSVProcessorPlugin extends Plugin implements DataProcessor {onInitialize(): void {console.log("CSV处理器准备就绪");}onDestroy(): void {console.log("CSV处理器已清理");}processData(input: object): object {console.log("处理CSV数据");return input;}supportsFormat(format: string): boolean {return format === "csv";}
}class DashboardPlugin extends Plugin implements UIComponent, DataProcessor {onInitialize(): void {console.log("仪表盘插件准备就绪");}onDestroy(): void {console.log("仪表盘插件已清理");}render(): void {console.log("渲染仪表盘UI");}getUIConfig(): object {return { type: "dashboard" };}processData(input: object): object {console.log("仪表盘数据处理");return input;}supportsFormat(format: string): boolean {return format === "json" || format === "csv";}
}// 插件管理器
class PluginManager {private plugins: Plugin[] = [];private dataProcessors: DataProcessor[] = [];registerPlugin(plugin: Plugin): void {this.plugins.push(plugin);plugin.initialize();// 如果插件实现了DataProcessor,额外注册if (this.isDataProcessor(plugin)) {this.dataProcessors.push(plugin);}}private isDataProcessor(plugin: Plugin): plugin is Plugin & DataProcessor {return "processData" in plugin && "supportsFormat" in plugin;}processDataByFormat(format: string, data: object): object | null {for (let processor of this.dataProcessors) {if (processor.supportsFormat(format)) {return processor.processData(data);}}return null;}
}

第五部分:小结与练习

知识点对比总结表

概念 核心语法 适用场景
Interface interface A { ... } 定义对象结构、类契约
实现接口 class C implements A, B 给类添加能力
接口继承 interface A extends B 扩展接口定义
抽象类 abstract class A 共享代码实现
type别名 type ID = number 基本类型、联合类型、函数类型

Interface vs Abstract Class 速记:

  • Interface = "能做什么"(能力清单)
  • Abstract Class = "是什么 + 能做什么"(身份 + 能力 + 默认实现)

练习题

练习1:基础接口定义

// 1. 定义Vehicle接口:
//    - 属性:brand(字符串), model(字符串), year(数字)
//    - 可选属性:color(字符串)
//    - 方法:start(): void, stop(): void// 2. 定义Electric接口(电动车特性):
//    - 属性:batteryCapacity(数字,单位kWh)
//    - 方法:charge(hours: number): void// 3. 定义Gasoline接口(燃油车特性):
//    - 属性:tankCapacity(数字,单位L)
//    - 方法:refuel(liters: number): void// 4. 创建Car类实现Vehicle接口
// 5. 创建ElectricCar类继承Car并实现Electric接口
// 6. 创建HybridCar类继承Car并实现Electric和Gasoline接口
点击查看答案
interface Vehicle {brand: string;model: string;year: number;color?: string;start(): void;stop(): void;
}interface Electric {batteryCapacity: number;charge(hours: number): void;
}interface Gasoline {tankCapacity: number;refuel(liters: number): void;
}class Car implements Vehicle {brand: string;model: string;year: number;constructor(b: string, m: string, y: number) {this.brand = b;this.model = m;this.year = y;}start(): void { console.log("car start"); }stop(): void { console.log("car stop"); }
}class ElectricCar extends Car implements Electric {batteryCapacity: number;constructor(b: string, m: string, y: number, bc: number) {super(b, m, y);this.batteryCapacity = bc;}charge(hours: number): void {}
}class HybridCar extends Car implements Electric, Gasoline {batteryCapacity: number;tankCapacity: number;constructor(b: string, m: string, y: number, bc: number, tc: number) {super(b, m, y);this.batteryCapacity = bc;this.tankCapacity = tc;}charge(hours: number): void {}refuel(liters: number): void {}
}

练习2:接口继承与合并

// 1. 定义基础接口BaseEntity:
//    - 属性:id(数字), createdAt(数字)// 2. 定义SoftDelete接口:
//    - 属性:isDeleted(布尔值), deletedAt?(数字)// 3. 定义Versioned接口:
//    - 属性:version(数字)// 4. 定义Auditable接口继承BaseEntity,并包含:
//    - 属性:createdBy(字符串), updatedAt(数字)// 5. 定义FullEntity接口继承Auditable、SoftDelete、Versioned
//    思考:这些接口的属性会合并吗?有没有冲突?// 6. 实现一个Document类实现FullEntity接口
点击查看答案
interface BaseEntity {id: number;createAt: number;
}interface SoftDelete {isDeleted: boolean;deleteAt?: number;
}interface Versioned {version: number;
}interface Auditable extends BaseEntity {createBy: string;updateAt: number;
}interface FullEntity extends Auditable, SoftDelete, Versioned {}class Document implements FullEntity {createBy: string;updateAt: number;id: number;createAt: number;isDeleted: boolean;version: number;deleteAt?: number;constructor() {this.createBy = "thomas";this.updateAt = 1;this.id = 1;this.createAt = 1;this.isDeleted = false;this.version = 1;}
}

分析:

  • 属性会正常合并,没有冲突
  • FullEntity 最终包含:id, createAt, createBy, updateAt, isDeleted, deleteAt?, version
  • deleteAt 保持可选,其他都是必需的

练习3:接口与抽象类结合

// 1. 定义Logger抽象类:
//    - 属性:name(字符串), level(字符串,默认"info")
//    - 方法:log(message: string): void(具体方法,打印日志)
//    - 抽象方法:writeOutput(message: string): void// 2. 定义Rotatable接口:
//    - 方法:rotate(): void// 3. 定义FileLogger类继承Logger:
//    - 实现writeOutput方法(模拟写入文件)// 4. 定义RotatingFileLogger类继承FileLogger实现Rotatable接口:
//    - 实现rotate方法(模拟日志轮转)// 5. 创建实例测试所有功能
点击查看答案
abstract class Logger {name: string = "";level: string = "info";abstract writeOutput(message: string): void;log(message: string): void {console.log(`[${this.level}]${message}`);}
}interface Rotatable {rotate(): void;
}class FileLogger extends Logger {writeOutput(message: string): void {}
}class RotatingFileLogger extends FileLogger implements Rotatable {rotate(): void {}
}

练习4:多接口实现设计

// 设计一个多媒体播放器系统:// 1. 定义Playable接口(可播放):
//    - 方法:play(), pause(), stop()
//    - 属性:isPlaying(布尔值)// 2. 定义Recordable接口(可录制):
//    - 方法:startRecording(), stopRecording()
//    - 属性:isRecording(布尔值)// 3. 定义Streamable接口(可流媒体):
//    - 方法:connect(url: string), disconnect()
//    - 属性:bufferLevel(数字)// 4. 实现以下类:
//    - AudioPlayer:实现Playable
//    - VideoPlayer:实现Playable和Streamable
//    - ScreenRecorder:实现Recordable和Streamable
//    - LiveStreamer:实现Playable、Recordable、Streamable// 5. 编写函数统一处理Playable设备
点击查看答案
interface Playable {isPlaying: boolean;play(): void;pause(): void;stop(): void;
}interface Recordable {isRecording: boolean;startRecording(): void;stopRecording(): void;
}interface Streamable {bufferLevel: number;connect(url: string): void;disconnect(): void;
}class AudioPlayer implements Playable {isPlaying: boolean = false;play(): void {}pause(): void {}stop(): void {}
}class VideoPlayer implements Playable, Streamable {isPlaying: boolean = false;bufferLevel: number = 0;play(): void {}pause(): void {}stop(): void {}connect(url: string): void {}disconnect(): void {}
}class ScreenRecorder implements Recordable, Streamable {isRecording: boolean = false;bufferLevel: number = 0;startRecording(): void {}stopRecording(): void {}connect(url: string): void {}disconnect(): void {}
}class LiveStreamer implements Playable, Recordable, Streamable {bufferLevel: number = 15;isPlaying: boolean = false;isRecording: boolean = false;connect(url: string): void {}disconnect(): void {}startRecording(): void {}stopRecording(): void {}play(): void {}pause(): void {}stop(): void {}
}// 统一处理Playable设备
function controlPlayback(device: Playable): void {console.log("控制播放设备");device.play();
}// 使用示例
let audio = new AudioPlayer();
let video = new VideoPlayer();
controlPlayback(audio);
controlPlayback(video);

练习5:接口成员合并规则应用

// 分析以下代码,找出问题并修正:interface ConfigA {timeout: number;retry: number;        // 必需属性
}interface ConfigB {timeout: number;retry?: number;       // 可选属性
}// 类实现时报错,为什么?如何修正?
class Settings implements ConfigA, ConfigB {timeout: number = 5000;retry?: number = 3;   // ❌ 报错!
}// 请提供修正方案

提示:

  • ConfigA 要求 retry 是必需的
  • ConfigB 要求 retry 是可选的
  • 类实现时 retry 的可选性必须满足更严格的要求
点击查看答案

错误原因:
ConfigA 要求 retry 是必需属性,但 Settings 类中将其声明为可选属性 retry?: number,不满足 ConfigA 的要求。

修正方案:

class Settings implements ConfigA, ConfigB {timeout: number = 5000;retry: number = 3;    // ✅ 正确,改为必需属性
}

核心规则:

  • 接口合并时,同名属性按最严格要求处理
  • 类实现时,属性必须满足所有接口的要求
  • 可选性冲突时,实现类必须使用更严格的(必需)

练习6:设计模式应用

// 使用接口实现策略模式(Strategy Pattern):// 1. 定义PaymentStrategy接口:
//    - 方法:pay(amount: number): boolean
//    - 方法:getName(): string// 2. 实现以下策略:
//    - CreditCardStrategy:信用卡支付
//    - AlipayStrategy:支付宝支付
//    - WeChatPayStrategy:微信支付// 3. 定义PaymentContext类:
//    - 属性:strategy(PaymentStrategy)
//    - 方法:setStrategy(strategy: PaymentStrategy): void
//    - 方法:executePayment(amount: number): void// 4. 演示运行时切换支付策略
点击查看答案
interface PaymentStrategy {pay(amount: number): boolean;getName(): string;
}class CreditCardStrategy implements PaymentStrategy {pay(amount: number): boolean {console.log(`use ${this.getName()} pay:${amount}`);return true;}getName(): string {return "CreditCard";}
}class AlipayStrategy implements PaymentStrategy {pay(amount: number): boolean {console.log(`use ${this.getName()} pay:${amount}`);return true;}getName(): string {return "Alipay";}
}class WeChatPayStrategy implements PaymentStrategy {pay(amount: number): boolean {console.log(`use ${this.getName()} pay:${amount}`);return true;}getName(): string {return "WeChatPay";}
}class PaymentContext {strategy: PaymentStrategy;constructor(strategy: PaymentStrategy) {this.strategy = strategy;}setStrategy(strategy: PaymentStrategy): void {this.strategy = strategy;}executePayment(amount: number): void {this.strategy.pay(amount);}
}// 演示运行时切换
function test(): void {let cc = new CreditCardStrategy();let ap = new AlipayStrategy();let wp = new WeChatPayStrategy();let pc = new PaymentContext(cc);pc.executePayment(12);    // 信用卡支付pc.setStrategy(ap);pc.executePayment(45);    // 支付宝支付pc.setStrategy(wp);pc.executePayment(13);    // 微信支付
}

设计模式优势:

  • 开闭原则:新增支付方式只需添加新类
  • 解耦:PaymentContext 不依赖具体支付方式
  • 运行时切换:动态改变行为

附录:C++ vs ArkTS 接口对比速查

概念 C++ ArkTS
接口定义 纯虚基类 class I { virtual void f() = 0; }; interface I { f(): void; }
实现接口 class C : public I class C implements I
多实现 多重继承(有风险) implements A, B, C(安全)
接口继承 class IA : public IB interface IA extends IB
可选成员 无直接语法 prop?: type
构造函数 可以有 不能有
成员变量 可以有 只能声明属性类型
默认实现 可以有 不能有
http://www.jsqmd.com/news/645608/

相关文章:

  • 智慧AI甲骨文检测 目标检测图像数据集 甲骨文识别第10341期
  • 2025终极指南:如何用免费工具突破网盘限速,下载速度提升10倍!
  • SITS2026评审通过率提升3.8倍的关键动作:如何用1份技术白皮书+2个可运行Demo打动专家团?
  • Spring Boot项目里,5分钟搞定LangChain4j调用本地Ollama模型(附完整代码)
  • 避坑指南:安装PyTorch扩展库时如何防止CUDA失效(torch-sparse/torch-scatter实战案例)
  • 智慧AI识别之建筑外墙霉斑识别 建筑物墙面渗水识别 墙体结构等场景的缺陷检测 建筑物安全监测 房屋维护维修识别 yolo格式第10427期 (1)
  • 2026奇点智能技术大会刚闭幕,这7个AI编程工具真实表现已刷新认知:谁在复杂微服务重构中零误报?谁在中文注释理解上仍卡壳?
  • 别再手动写Getter/Setter了!IntelliJ IDEA + Lombok 1.18.42 保姆级配置与实战避坑指南
  • 李开复陆奇重仓同一家Harness智能体公司,李笛带队,4个月2轮融资3-5年粮草
  • Finnhub Python API终极指南:3分钟掌握机构级金融数据获取
  • 【2020 顶刊 trans复现】 基于双曲-正切 HLOS 制导和有限时间控制的欠驱动无人船路径跟随控制MATLAB源码
  • 为什么你的多模态微调效果总比SOTA低12.6%?——数据质量熵值超标警报与5维可审计质检看板搭建(含Prometheus+Grafana监控模板)
  • 清华密度定律-同等智能每35个月减半
  • 新手避坑指南:第一次用Python控制IT6500电源就遇到的5个问题(附解决方案)
  • 路径规划算法实战指南:从Dijkstra到RRT*的演进与应用
  • Rust的#[inline(never)]函数属性与调试信息在性能分析中的保留
  • Halcon图像处理入门:5分钟搞定空白图像创建与多通道合并(附代码示例)
  • 别再买贵的了!手把手教你用STM32和开源硬件DIY一个CANable USB-CAN适配器
  • 2026年不侵权高清图片素材网站合集:免费大图下载、正版商用网站全收录 - 品牌2026
  • SITS2026多模态融合技术白皮书核心泄露(2024Q2唯一授权解读版):跨模态对齐、时序耦合、轻量化蒸馏三重瓶颈突破
  • 智慧AI隧道场景识别 隧道火灾识别数据集 隧道交通事故数据集 隧道运营安全与应急响应报警识别数据集 隧道安全监控图像第10253期
  • FAST-LIO2主从部署实战(一):ROS环境与Livox驱动配置全解
  • 信号与系统:s域分析法在电路瞬态响应中的实战应用
  • UE5.5编译报错“内存访问冲突”?手把手教你通过修改BuildConfiguration.xml文件解决UBA问题
  • 【C语言】-自定义类型:结构体
  • RKNN模型部署实战:对比RKNN Toolkit2与Lite2,在RK3588上如何选择与切换?
  • 多模态模型灰度发布必须绕开的7个反模式,92%团队已在第4步 silently rollback
  • 多模态健身指导不是“加摄像头+加麦克风”,而是重构感知-决策-反馈闭环:奇点大会披露的12层异构融合推理引擎架构
  • Python字体处理终极指南:fontTools库的完整实践手册
  • 2026年纸箱包装全行业深度横评:从普箱到精品礼盒,如何选择梓童包装等优质供应商 - 精选优质企业推荐榜