类与面向对象编程
2026/7/9大约 5 分钟
类与面向对象编程
概述
Go 采用基于结构体(struct)的组合式面向对象,不提供 class 关键字,也没有传统意义上的继承。TypeScript 则提供了完整的基于 class 的 OOP 支持:构造函数、访问修饰符、抽象类、继承、接口实现等。对于 Go 开发者,理解这些概念的核心差异是掌握 TS OOP 的关键。
Go 开发者已知
// Go 的"类"——结构体+方法
type User struct {
Name string
Age int
}
// 方法(值接收者)
func (u User) Greet() string {
return fmt.Sprintf("Hi, I'm %s", u.Name)
}
// 方法(指针接收者——可变)
func (u *User) Birthday() {
u.Age++
}
// 嵌入——Go 的组合替代继承
type Admin struct {
User // 嵌入字段
Role string
}
// 接口——隐式实现
type Stringer interface {
String() string
}
func (u User) String() string {
return u.Name
}
// 构造函数(习惯约定)
func NewUser(name string, age int) *User {
return &User{Name: name, Age: age}
}Go OOP 特点:
- 无
class关键字,用struct+ 方法实现 - 组合优先于继承(通过嵌入)
- 没有访问修饰符(首字母大小写控制可见性)
- 没有
this关键字(显式接收者) - 没有构造函数(工厂函数模式)
TypeScript 怎么做
class 基础
class User {
// 属性声明
name: string
age: number
// 构造函数
constructor(name: string, age: number) {
this.name = name
this.age = age
}
// 方法
greet(): string {
return `Hi, I'm ${this.name}`
}
birthday(): void {
this.age++
}
}
// 使用
const user = new User('Alice', 30)
user.greet() // "Hi, I'm Alice"
user.birthday() // age -> 31访问修饰符
class Person {
public name: string // 公开(默认)
private ssn: string // 私有(仅在类内可访问)
protected id: number // 受保护(类及子类可访问)
readonly birthDate: Date // 只读
constructor(name: string, ssn: string, birthDate: Date) {
this.name = name
this.ssn = ssn
this.id = Math.random()
this.birthDate = birthDate
}
getInfo(): string {
return `${this.name} (${this.id})`
}
}
// 参数属性简写
class CompactPerson {
constructor(
public name: string,
private ssn: string,
readonly birthDate: Date,
protected id: number = Math.random(),
) {}
}implements 实现接口
interface IUser {
name: string
greet(): string
}
// 显式实现(与 Go 的隐式实现不同)
class RealUser implements IUser {
constructor(public name: string) {}
greet(): string {
return `Hello, ${this.name}`
}
}abstract 抽象类
abstract class Animal {
abstract makeSound(): void // 抽象方法
move(): void {
console.log('Moving...')
}
}
class Dog extends Animal {
makeSound(): void {
console.log('Woof!')
}
}
// const a = new Animal() // Error: 无法实例化抽象类extends 继承
class Animal {
constructor(public name: string) {}
speak(): void {
console.log(`${this.name} makes a sound`)
}
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name) // 必须调用父类构造函数
}
// 重写
speak(): void {
super.speak() // 调用父类方法
console.log('Woof!')
}
}Getter / Setter
class Temperature {
private _celsius = 0
get celsius(): number {
return this._celsius
}
set celsius(value: number) {
if (value < -273.15) {
throw new Error('Below absolute zero')
}
this._celsius = value
}
get fahrenheit(): number {
return this._celsius * 9 / 5 + 32
}
}static 成员
class Config {
static readonly VERSION = '1.0.0'
private static instances = 0
static getInstanceCount(): number {
return Config.instances
}
constructor() {
Config.instances++
}
}
console.log(Config.VERSION)差异分析
| 维度 | Go | TypeScript |
|---|---|---|
| 类定义 | struct + 方法 | class 关键字 |
| 构造函数 | 工厂函数 NewXxx() | constructor() |
| 访问控制 | 首字母大小写 | public/private/protected |
| 继承 | 结构体嵌入(组合) | extends 继承 |
| 接口实现 | 隐式 | 显式 implements |
| 抽象类 | 无(interface 可有方法) | abstract class |
| Getter/Setter | 方法约定 GetXxx() | get/set 关键字 |
| this | 显式接收者 | 隐式 this(有闭包问题) |
| 多态 | 接口 + 类型断言 | 继承 + 结构化类型 |
| 值/引用 | 值传递,指针可变 | 对象引用 |
Go 的嵌入 vs TS 的继承
Go 的嵌入本质是组合,子类型"拥有"父结构体的字段和方法,但在类型系统中两者是不同的类型。
// Go 嵌入
type Animal struct { Name string }
func (a Animal) Speak() {}
type Dog struct { Animal } // Dog 拥有 Animal 的字段和方法
var d Dog
d.Speak() // OK,方法提升
var a Animal = d // Error: 类型不兼容TS 的 extends 是继承,子类是父类的子类型:
class Animal { constructor(public name: string) {} }
class Dog extends Animal {}
const d = new Dog('Rex')
const a: Animal = d // OK,Dog 是 Animal 的子类型Bad Practice
// Bad: 过度继承(多层继承链)
class A { }
class B extends A { }
class C extends B { }
class D extends C { }
class E extends D { } // 5 层继承!难以维护
// Bad: 在 getter 中做副作用操作
class Cart {
private _items: string[] = []
get items(): string[] {
console.log('Items accessed') // 副作用
return this._items
}
}
// Bad: 暴露内部可变数组引用
class Team {
private members: string[] = []
getMembers(): string[] {
return this.members // 外部可以修改内部状态!
}
}
// Bad: TypeScript 中的继承过深
class Shape {}
class Polygon extends Shape {}
class Rectangle extends Polygon {}
class Square extends Rectangle {} // 经典 OOP 反模式Best Practice
// Good: 优先组合,而非继承
interface Flyable {
fly(): void
}
interface Swimmable {
swim(): void
}
class Duck implements Flyable, Swimmable {
fly() { console.log('Flying') }
swim() { console.log('Swimming') }
}
// Good: 返回不可变数据
class Team {
constructor(private members: string[]) {}
getMembers(): readonly string[] {
return [...this.members] // 返回副本
}
}
// Good: 参数属性简写
class User {
constructor(
public readonly id: number,
public name: string,
private password: string,
) {}
}
// Good: 使用私有构造函数 + 静态工厂方法
class DatabaseConnection {
private constructor(private url: string) {}
static async create(url: string): Promise<DatabaseConnection> {
const conn = new DatabaseConnection(url)
await conn.connect()
return conn
}
private async connect(): Promise<void> {
// 初始化连接
}
}
// Good: 使用 readonly 防止意外修改
class ConfigReader {
constructor(readonly config: Record<string, string>) {}
}
// Good: 接口隔离(Interface Segregation)
interface Reader {
read(): string
}
interface Writer {
write(data: string): void
}
class FileIO implements Reader, Writer {
read() { return 'content' }
write(data: string) { console.log(data) }
}组合 vs 继承
Go 开发者的直觉是"组合优先",这个原则在 TypeScript 中同样适用。
优先组合:
- 使用
interface定义行为契约 - 使用
class implements多个接口 - 用依赖注入替代继承
组合无法替代时使用继承:
- 层次结构明确的领域模型
- 需要复用大部分实现
- 框架强制要求(如 React 类组件)
code-tabs 对比
总结
| Go 概念 | TypeScript 对应 |
|---|---|
struct + 方法 | class |
工厂函数 NewXxx() | constructor() |
| 嵌入(组合) | extends(继承)或 implements(接口) |
| 首字母大小写控制可见性 | public/private/protected |
| 隐式接口实现 | 显式 implements |
| Getter/Setter 方法 | get/set 属性访问器 |
| 指针接收者 | 类方法默认引用语义 |
核心认知:TypeScript 的 class 系统更接近传统 OOP 语言(Java/C++),而 Go 的组合模式更加简洁。在 TS 中同样应遵循组合优先原则,避免过度继承。
下一章将介绍 泛型编程。