13.1 架构设计原则

13.1.1 SOLID原则在TypeScript中的应用

// src/principles/solid.ts - SOLID原则示例

// 1. 单一职责原则 (Single Responsibility Principle)
interface UserRepository {
  findById(id: string): Promise<User | null>;
  save(user: User): Promise<void>;
  delete(id: string): Promise<void>;
}

interface UserValidator {
  validate(user: User): ValidationResult;
}

interface EmailService {
  sendWelcomeEmail(user: User): Promise<void>;
}

// 错误示例:违反单一职责原则
class BadUserService {
  async createUser(userData: CreateUserRequest): Promise<User> {
    // 验证用户数据
    if (!userData.email || !userData.password) {
      throw new Error('Invalid user data');
    }
    
    // 保存用户
    const user = new User(userData);
    await this.saveToDatabase(user);
    
    // 发送邮件
    await this.sendEmail(user.email, 'Welcome!');
    
    // 记录日志
    console.log(`User created: ${user.id}`);
    
    return user;
  }
  
  private async saveToDatabase(user: User): Promise<void> { /* ... */ }
  private async sendEmail(email: string, subject: string): Promise<void> { /* ... */ }
}

// 正确示例:遵循单一职责原则
class UserService {
  constructor(
    private userRepository: UserRepository,
    private userValidator: UserValidator,
    private emailService: EmailService,
    private logger: Logger
  ) {}
  
  async createUser(userData: CreateUserRequest): Promise<User> {
    // 验证
    const validationResult = this.userValidator.validate(userData);
    if (!validationResult.isValid) {
      throw new ValidationError(validationResult.errors);
    }
    
    // 创建用户
    const user = new User(userData);
    
    // 保存
    await this.userRepository.save(user);
    
    // 发送欢迎邮件
    await this.emailService.sendWelcomeEmail(user);
    
    // 记录日志
    this.logger.info(`User created: ${user.id}`);
    
    return user;
  }
}

// 2. 开闭原则 (Open/Closed Principle)
abstract class PaymentProcessor {
  abstract processPayment(amount: number, paymentMethod: PaymentMethod): Promise<PaymentResult>;
  
  protected validateAmount(amount: number): void {
    if (amount <= 0) {
      throw new Error('Amount must be positive');
    }
  }
}

class CreditCardProcessor extends PaymentProcessor {
  async processPayment(amount: number, paymentMethod: CreditCardPayment): Promise<PaymentResult> {
    this.validateAmount(amount);
    
    // 信用卡特定的处理逻辑
    const result = await this.chargeCreditCard(amount, paymentMethod.cardNumber);
    return result;
  }
  
  private async chargeCreditCard(amount: number, cardNumber: string): Promise<PaymentResult> {
    // 信用卡支付逻辑
    return { success: true, transactionId: 'cc_' + Date.now() };
  }
}

class PayPalProcessor extends PaymentProcessor {
  async processPayment(amount: number, paymentMethod: PayPalPayment): Promise<PaymentResult> {
    this.validateAmount(amount);
    
    // PayPal特定的处理逻辑
    const result = await this.chargePayPal(amount, paymentMethod.email);
    return result;
  }
  
  private async chargePayPal(amount: number, email: string): Promise<PaymentResult> {
    // PayPal支付逻辑
    return { success: true, transactionId: 'pp_' + Date.now() };
  }
}

// 3. 里氏替换原则 (Liskov Substitution Principle)
interface Bird {
  move(): void;
}

interface FlyingBird extends Bird {
  fly(): void;
}

interface SwimmingBird extends Bird {
  swim(): void;
}

class Eagle implements FlyingBird {
  move(): void {
    this.fly();
  }
  
  fly(): void {
    console.log('Eagle is flying');
  }
}

class Penguin implements SwimmingBird {
  move(): void {
    this.swim();
  }
  
  swim(): void {
    console.log('Penguin is swimming');
  }
}

// 4. 接口隔离原则 (Interface Segregation Principle)
// 错误示例:臃肿的接口
interface BadWorker {
  work(): void;
  eat(): void;
  sleep(): void;
  code(): void;
  design(): void;
  test(): void;
}

// 正确示例:细分的接口
interface Worker {
  work(): void;
}

interface Human {
  eat(): void;
  sleep(): void;
}

interface Developer {
  code(): void;
}

interface Designer {
  design(): void;
}

interface Tester {
  test(): void;
}

class SoftwareDeveloper implements Worker, Human, Developer {
  work(): void {
    this.code();
  }
  
  eat(): void {
    console.log('Developer is eating');
  }
  
  sleep(): void {
    console.log('Developer is sleeping');
  }
  
  code(): void {
    console.log('Developer is coding');
  }
}

// 5. 依赖倒置原则 (Dependency Inversion Principle)
interface NotificationService {
  send(message: string, recipient: string): Promise<void>;
}

class EmailNotificationService implements NotificationService {
  async send(message: string, recipient: string): Promise<void> {
    console.log(`Sending email to ${recipient}: ${message}`);
  }
}

class SMSNotificationService implements NotificationService {
  async send(message: string, recipient: string): Promise<void> {
    console.log(`Sending SMS to ${recipient}: ${message}`);
  }
}

// 高层模块依赖抽象,而不是具体实现
class OrderService {
  constructor(private notificationService: NotificationService) {}
  
  async processOrder(order: Order): Promise<void> {
    // 处理订单逻辑
    await this.saveOrder(order);
    
    // 发送通知
    await this.notificationService.send(
      `Order ${order.id} has been processed`,
      order.customerEmail
    );
  }
  
  private async saveOrder(order: Order): Promise<void> {
    // 保存订单逻辑
  }
}

13.1.2 领域驱动设计 (DDD)

// src/domain/user/entities/User.ts - 用户实体
export class User {
  private constructor(
    private readonly _id: UserId,
    private _email: Email,
    private _profile: UserProfile,
    private _status: UserStatus,
    private readonly _createdAt: Date,
    private _updatedAt: Date
  ) {}
  
  static create(email: string, profile: UserProfileData): User {
    const userId = UserId.generate();
    const userEmail = Email.create(email);
    const userProfile = UserProfile.create(profile);
    
    return new User(
      userId,
      userEmail,
      userProfile,
      UserStatus.ACTIVE,
      new Date(),
      new Date()
    );
  }
  
  static fromPersistence(data: UserPersistenceData): User {
    return new User(
      UserId.fromString(data.id),
      Email.create(data.email),
      UserProfile.fromPersistence(data.profile),
      UserStatus.fromString(data.status),
      new Date(data.createdAt),
      new Date(data.updatedAt)
    );
  }
  
  // Getters
  get id(): UserId { return this._id; }
  get email(): Email { return this._email; }
  get profile(): UserProfile { return this._profile; }
  get status(): UserStatus { return this._status; }
  get createdAt(): Date { return this._createdAt; }
  get updatedAt(): Date { return this._updatedAt; }
  
  // 业务方法
  updateEmail(newEmail: string): void {
    const email = Email.create(newEmail);
    this._email = email;
    this._updatedAt = new Date();
    
    // 发布领域事件
    DomainEvents.raise(new UserEmailUpdatedEvent(this._id, email));
  }
  
  updateProfile(profileData: UserProfileData): void {
    this._profile = UserProfile.create(profileData);
    this._updatedAt = new Date();
    
    DomainEvents.raise(new UserProfileUpdatedEvent(this._id, this._profile));
  }
  
  deactivate(): void {
    if (this._status === UserStatus.INACTIVE) {
      throw new DomainError('User is already inactive');
    }
    
    this._status = UserStatus.INACTIVE;
    this._updatedAt = new Date();
    
    DomainEvents.raise(new UserDeactivatedEvent(this._id));
  }
  
  activate(): void {
    if (this._status === UserStatus.ACTIVE) {
      throw new DomainError('User is already active');
    }
    
    this._status = UserStatus.ACTIVE;
    this._updatedAt = new Date();
    
    DomainEvents.raise(new UserActivatedEvent(this._id));
  }
  
  toPersistence(): UserPersistenceData {
    return {
      id: this._id.value,
      email: this._email.value,
      profile: this._profile.toPersistence(),
      status: this._status.value,
      createdAt: this._createdAt.toISOString(),
      updatedAt: this._updatedAt.toISOString()
    };
  }
}

// src/domain/user/value-objects/UserId.ts - 用户ID值对象
export class UserId {
  private constructor(private readonly _value: string) {
    this.validate(_value);
  }
  
  static generate(): UserId {
    return new UserId(crypto.randomUUID());
  }
  
  static fromString(value: string): UserId {
    return new UserId(value);
  }
  
  get value(): string {
    return this._value;
  }
  
  equals(other: UserId): boolean {
    return this._value === other._value;
  }
  
  private validate(value: string): void {
    if (!value || typeof value !== 'string') {
      throw new DomainError('UserId must be a non-empty string');
    }
    
    // UUID格式验证
    const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
    if (!uuidRegex.test(value)) {
      throw new DomainError('UserId must be a valid UUID');
    }
  }
}

// src/domain/user/value-objects/Email.ts - 邮箱值对象
export class Email {
  private constructor(private readonly _value: string) {
    this.validate(_value);
  }
  
  static create(value: string): Email {
    return new Email(value);
  }
  
  get value(): string {
    return this._value;
  }
  
  get domain(): string {
    return this._value.split('@')[1];
  }
  
  get localPart(): string {
    return this._value.split('@')[0];
  }
  
  equals(other: Email): boolean {
    return this._value.toLowerCase() === other._value.toLowerCase();
  }
  
  private validate(value: string): void {
    if (!value || typeof value !== 'string') {
      throw new DomainError('Email must be a non-empty string');
    }
    
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(value)) {
      throw new DomainError('Invalid email format');
    }
    
    if (value.length > 254) {
      throw new DomainError('Email is too long');
    }
  }
}

// src/domain/user/repositories/UserRepository.ts - 用户仓储接口
export interface UserRepository {
  findById(id: UserId): Promise<User | null>;
  findByEmail(email: Email): Promise<User | null>;
  save(user: User): Promise<void>;
  delete(id: UserId): Promise<void>;
  findAll(criteria?: UserSearchCriteria): Promise<User[]>;
  count(criteria?: UserSearchCriteria): Promise<number>;
}

export interface UserSearchCriteria {
  status?: UserStatus;
  emailDomain?: string;
  createdAfter?: Date;
  createdBefore?: Date;
  limit?: number;
  offset?: number;
}

// src/domain/user/services/UserDomainService.ts - 领域服务
export class UserDomainService {
  constructor(private userRepository: UserRepository) {}
  
  async isEmailUnique(email: Email, excludeUserId?: UserId): Promise<boolean> {
    const existingUser = await this.userRepository.findByEmail(email);
    
    if (!existingUser) {
      return true;
    }
    
    if (excludeUserId && existingUser.id.equals(excludeUserId)) {
      return true;
    }
    
    return false;
  }
  
  async canUserBeDeleted(userId: UserId): Promise<boolean> {
    // 检查用户是否有未完成的订单、活跃的会话等
    // 这里可能需要调用其他聚合根的仓储
    return true; // 简化实现
  }
}

// src/domain/user/events/UserEvents.ts - 领域事件
export abstract class UserDomainEvent {
  constructor(
    public readonly userId: UserId,
    public readonly occurredAt: Date = new Date()
  ) {}
}

export class UserCreatedEvent extends UserDomainEvent {
  constructor(
    userId: UserId,
    public readonly email: Email,
    public readonly profile: UserProfile
  ) {
    super(userId);
  }
}

export class UserEmailUpdatedEvent extends UserDomainEvent {
  constructor(
    userId: UserId,
    public readonly newEmail: Email
  ) {
    super(userId);
  }
}

export class UserDeactivatedEvent extends UserDomainEvent {
  constructor(userId: UserId) {
    super(userId);
  }
}

13.2 微服务架构

13.2.1 服务拆分策略

// src/services/user-service/types/index.ts - 用户服务类型定义
export interface UserServiceConfig {
  database: {
    host: string;
    port: number;
    database: string;
    username: string;
    password: string;
  };
  redis: {
    host: string;
    port: number;
    password?: string;
  };
  messaging: {
    brokerUrl: string;
    exchange: string;
  };
  auth: {
    jwtSecret: string;
    jwtExpiresIn: string;
  };
}

export interface UserServiceAPI {
  // 用户管理
  createUser(request: CreateUserRequest): Promise<CreateUserResponse>;
  getUserById(id: string): Promise<GetUserResponse>;
  updateUser(id: string, request: UpdateUserRequest): Promise<UpdateUserResponse>;
  deleteUser(id: string): Promise<void>;
  
  // 认证相关
  authenticate(request: AuthenticateRequest): Promise<AuthenticateResponse>;
  refreshToken(request: RefreshTokenRequest): Promise<RefreshTokenResponse>;
  
  // 查询
  searchUsers(request: SearchUsersRequest): Promise<SearchUsersResponse>;
  getUsersByIds(ids: string[]): Promise<GetUsersResponse>;
}

// src/services/user-service/application/UserApplicationService.ts - 应用服务
export class UserApplicationService implements UserServiceAPI {
  constructor(
    private userRepository: UserRepository,
    private userDomainService: UserDomainService,
    private passwordService: PasswordService,
    private tokenService: TokenService,
    private eventBus: EventBus,
    private logger: Logger
  ) {}
  
  async createUser(request: CreateUserRequest): Promise<CreateUserResponse> {
    try {
      // 验证请求
      const validationResult = await this.validateCreateUserRequest(request);
      if (!validationResult.isValid) {
        throw new ValidationError(validationResult.errors);
      }
      
      // 检查邮箱唯一性
      const email = Email.create(request.email);
      const isEmailUnique = await this.userDomainService.isEmailUnique(email);
      if (!isEmailUnique) {
        throw new BusinessError('Email already exists');
      }
      
      // 创建用户
      const hashedPassword = await this.passwordService.hash(request.password);
      const user = User.create(request.email, {
        firstName: request.firstName,
        lastName: request.lastName,
        hashedPassword
      });
      
      // 保存用户
      await this.userRepository.save(user);
      
      // 发布事件
      await this.eventBus.publish(new UserCreatedEvent(
        user.id,
        user.email,
        user.profile
      ));
      
      this.logger.info(`User created: ${user.id.value}`);
      
      return {
        id: user.id.value,
        email: user.email.value,
        profile: user.profile.toResponse(),
        createdAt: user.createdAt.toISOString()
      };
    } catch (error) {
      this.logger.error('Failed to create user', { error, request });
      throw error;
    }
  }
  
  async authenticate(request: AuthenticateRequest): Promise<AuthenticateResponse> {
    try {
      // 查找用户
      const email = Email.create(request.email);
      const user = await this.userRepository.findByEmail(email);
      
      if (!user) {
        throw new AuthenticationError('Invalid credentials');
      }
      
      // 验证密码
      const isPasswordValid = await this.passwordService.verify(
        request.password,
        user.profile.hashedPassword
      );
      
      if (!isPasswordValid) {
        throw new AuthenticationError('Invalid credentials');
      }
      
      // 检查用户状态
      if (user.status !== UserStatus.ACTIVE) {
        throw new AuthenticationError('User account is not active');
      }
      
      // 生成令牌
      const accessToken = await this.tokenService.generateAccessToken({
        userId: user.id.value,
        email: user.email.value
      });
      
      const refreshToken = await this.tokenService.generateRefreshToken({
        userId: user.id.value
      });
      
      this.logger.info(`User authenticated: ${user.id.value}`);
      
      return {
        accessToken,
        refreshToken,
        user: {
          id: user.id.value,
          email: user.email.value,
          profile: user.profile.toResponse()
        }
      };
    } catch (error) {
      this.logger.error('Authentication failed', { error, email: request.email });
      throw error;
    }
  }
  
  private async validateCreateUserRequest(request: CreateUserRequest): Promise<ValidationResult> {
    const errors: string[] = [];
    
    if (!request.email) {
      errors.push('Email is required');
    }
    
    if (!request.password || request.password.length < 8) {
      errors.push('Password must be at least 8 characters long');
    }
    
    if (!request.firstName) {
      errors.push('First name is required');
    }
    
    if (!request.lastName) {
      errors.push('Last name is required');
    }
    
    return {
      isValid: errors.length === 0,
      errors
    };
  }
}

13.2.2 服务间通信

// src/infrastructure/messaging/EventBus.ts - 事件总线
export interface EventBus {
  publish<T extends DomainEvent>(event: T): Promise<void>;
  subscribe<T extends DomainEvent>(
    eventType: string,
    handler: EventHandler<T>
  ): Promise<void>;
}

export interface EventHandler<T extends DomainEvent> {
  handle(event: T): Promise<void>;
}

export class RabbitMQEventBus implements EventBus {
  private connection: Connection | null = null;
  private channel: Channel | null = null;
  
  constructor(
    private config: RabbitMQConfig,
    private logger: Logger
  ) {}
  
  async connect(): Promise<void> {
    try {
      this.connection = await amqp.connect(this.config.url);
      this.channel = await this.connection.createChannel();
      
      // 声明交换机
      await this.channel.assertExchange(
        this.config.exchange,
        'topic',
        { durable: true }
      );
      
      this.logger.info('Connected to RabbitMQ');
    } catch (error) {
      this.logger.error('Failed to connect to RabbitMQ', { error });
      throw error;
    }
  }
  
  async publish<T extends DomainEvent>(event: T): Promise<void> {
    if (!this.channel) {
      throw new Error('EventBus not connected');
    }
    
    try {
      const routingKey = this.getRoutingKey(event);
      const message = JSON.stringify({
        eventId: crypto.randomUUID(),
        eventType: event.constructor.name,
        occurredAt: event.occurredAt.toISOString(),
        data: event
      });
      
      await this.channel.publish(
        this.config.exchange,
        routingKey,
        Buffer.from(message),
        {
          persistent: true,
          messageId: crypto.randomUUID(),
          timestamp: Date.now()
        }
      );
      
      this.logger.debug('Event published', { eventType: event.constructor.name, routingKey });
    } catch (error) {
      this.logger.error('Failed to publish event', { error, event });
      throw error;
    }
  }
  
  async subscribe<T extends DomainEvent>(
    eventType: string,
    handler: EventHandler<T>
  ): Promise<void> {
    if (!this.channel) {
      throw new Error('EventBus not connected');
    }
    
    try {
      const queueName = `${this.config.serviceName}.${eventType}`;
      const routingKey = this.getRoutingKeyPattern(eventType);
      
      // 声明队列
      await this.channel.assertQueue(queueName, {
        durable: true,
        arguments: {
          'x-dead-letter-exchange': `${this.config.exchange}.dlx`
        }
      });
      
      // 绑定队列到交换机
      await this.channel.bindQueue(queueName, this.config.exchange, routingKey);
      
      // 设置消费者
      await this.channel.consume(queueName, async (msg) => {
        if (!msg) return;
        
        try {
          const eventData = JSON.parse(msg.content.toString());
          await handler.handle(eventData.data);
          
          this.channel!.ack(msg);
          this.logger.debug('Event handled successfully', { eventType, queueName });
        } catch (error) {
          this.logger.error('Failed to handle event', { error, eventType, queueName });
          
          // 重试逻辑
          const retryCount = (msg.properties.headers?.['x-retry-count'] || 0) + 1;
          if (retryCount <= this.config.maxRetries) {
            // 延迟重试
            setTimeout(() => {
              this.channel!.nack(msg, false, true);
            }, this.config.retryDelay * retryCount);
          } else {
            // 发送到死信队列
            this.channel!.nack(msg, false, false);
          }
        }
      });
      
      this.logger.info('Subscribed to event', { eventType, queueName });
    } catch (error) {
      this.logger.error('Failed to subscribe to event', { error, eventType });
      throw error;
    }
  }
  
  private getRoutingKey(event: DomainEvent): string {
    const eventType = event.constructor.name;
    return `${this.config.serviceName}.${eventType}`;
  }
  
  private getRoutingKeyPattern(eventType: string): string {
    return `*.${eventType}`;
  }
  
  async disconnect(): Promise<void> {
    try {
      await this.channel?.close();
      await this.connection?.close();
      this.logger.info('Disconnected from RabbitMQ');
    } catch (error) {
      this.logger.error('Failed to disconnect from RabbitMQ', { error });
    }
  }
}

// src/infrastructure/http/ServiceClient.ts - HTTP服务客户端
export class ServiceClient {
  private httpClient: AxiosInstance;
  
  constructor(
    private config: ServiceClientConfig,
    private logger: Logger
  ) {
    this.httpClient = axios.create({
      baseURL: config.baseUrl,
      timeout: config.timeout || 30000,
      headers: {
        'Content-Type': 'application/json',
        'User-Agent': `${config.serviceName}/1.0.0`
      }
    });
    
    this.setupInterceptors();
  }
  
  private setupInterceptors(): void {
    // 请求拦截器
    this.httpClient.interceptors.request.use(
      (config) => {
        // 添加请求ID
        config.headers['X-Request-ID'] = crypto.randomUUID();
        
        // 添加认证令牌
        if (this.config.authToken) {
          config.headers['Authorization'] = `Bearer ${this.config.authToken}`;
        }
        
        this.logger.debug('HTTP request', {
          method: config.method,
          url: config.url,
          requestId: config.headers['X-Request-ID']
        });
        
        return config;
      },
      (error) => {
        this.logger.error('HTTP request error', { error });
        return Promise.reject(error);
      }
    );
    
    // 响应拦截器
    this.httpClient.interceptors.response.use(
      (response) => {
        this.logger.debug('HTTP response', {
          status: response.status,
          requestId: response.config.headers['X-Request-ID']
        });
        
        return response;
      },
      (error) => {
        const requestId = error.config?.headers['X-Request-ID'];
        
        if (error.response) {
          // 服务器响应错误
          this.logger.error('HTTP response error', {
            status: error.response.status,
            data: error.response.data,
            requestId
          });
        } else if (error.request) {
          // 网络错误
          this.logger.error('HTTP network error', {
            message: error.message,
            requestId
          });
        } else {
          // 其他错误
          this.logger.error('HTTP error', {
            message: error.message,
            requestId
          });
        }
        
        return Promise.reject(this.transformError(error));
      }
    );
  }
  
  async get<T>(path: string, params?: Record<string, any>): Promise<T> {
    const response = await this.httpClient.get(path, { params });
    return response.data;
  }
  
  async post<T>(path: string, data?: any): Promise<T> {
    const response = await this.httpClient.post(path, data);
    return response.data;
  }
  
  async put<T>(path: string, data?: any): Promise<T> {
    const response = await this.httpClient.put(path, data);
    return response.data;
  }
  
  async delete<T>(path: string): Promise<T> {
    const response = await this.httpClient.delete(path);
    return response.data;
  }
  
  private transformError(error: AxiosError): ServiceError {
    if (error.response) {
      const status = error.response.status;
      const data = error.response.data as any;
      
      switch (status) {
        case 400:
          return new ValidationError(data.message || 'Bad Request', data.errors);
        case 401:
          return new AuthenticationError(data.message || 'Unauthorized');
        case 403:
          return new AuthorizationError(data.message || 'Forbidden');
        case 404:
          return new NotFoundError(data.message || 'Not Found');
        case 409:
          return new ConflictError(data.message || 'Conflict');
        case 500:
          return new InternalServerError(data.message || 'Internal Server Error');
        default:
          return new ServiceError(data.message || 'Unknown Error', status);
      }
    } else if (error.request) {
      return new NetworkError('Network Error');
    } else {
      return new ServiceError(error.message || 'Unknown Error');
    }
  }
}

13.3 数据访问层设计

13.3.1 Repository模式实现

// src/infrastructure/persistence/UserRepositoryImpl.ts - 用户仓储实现
export class UserRepositoryImpl implements UserRepository {
  constructor(
    private db: Database,
    private logger: Logger,
    private cache: CacheService
  ) {}
  
  async findById(id: UserId): Promise<User | null> {
    try {
      // 先从缓存查找
      const cacheKey = `user:${id.value}`;
      const cachedData = await this.cache.get<UserPersistenceData>(cacheKey);
      
      if (cachedData) {
        this.logger.debug('User found in cache', { userId: id.value });
        return User.fromPersistence(cachedData);
      }
      
      // 从数据库查找
      const query = `
        SELECT u.*, p.first_name, p.last_name, p.hashed_password, p.avatar_url
        FROM users u
        LEFT JOIN user_profiles p ON u.id = p.user_id
        WHERE u.id = $1 AND u.deleted_at IS NULL
      `;
      
      const result = await this.db.query(query, [id.value]);
      
      if (result.rows.length === 0) {
        return null;
      }
      
      const userData = this.mapRowToUserData(result.rows[0]);
      const user = User.fromPersistence(userData);
      
      // 缓存结果
      await this.cache.set(cacheKey, userData, 3600); // 1小时
      
      this.logger.debug('User found in database', { userId: id.value });
      return user;
    } catch (error) {
      this.logger.error('Failed to find user by id', { error, userId: id.value });
      throw new RepositoryError('Failed to find user', error);
    }
  }
  
  async findByEmail(email: Email): Promise<User | null> {
    try {
      const query = `
        SELECT u.*, p.first_name, p.last_name, p.hashed_password, p.avatar_url
        FROM users u
        LEFT JOIN user_profiles p ON u.id = p.user_id
        WHERE LOWER(u.email) = LOWER($1) AND u.deleted_at IS NULL
      `;
      
      const result = await this.db.query(query, [email.value]);
      
      if (result.rows.length === 0) {
        return null;
      }
      
      const userData = this.mapRowToUserData(result.rows[0]);
      return User.fromPersistence(userData);
    } catch (error) {
      this.logger.error('Failed to find user by email', { error, email: email.value });
      throw new RepositoryError('Failed to find user', error);
    }
  }
  
  async save(user: User): Promise<void> {
    const client = await this.db.getClient();
    
    try {
      await client.query('BEGIN');
      
      const userData = user.toPersistence();
      
      // 检查用户是否已存在
      const existingUser = await this.findById(user.id);
      
      if (existingUser) {
        // 更新用户
        await this.updateUser(client, userData);
      } else {
        // 创建新用户
        await this.insertUser(client, userData);
      }
      
      await client.query('COMMIT');
      
      // 清除缓存
      const cacheKey = `user:${user.id.value}`;
      await this.cache.delete(cacheKey);
      
      this.logger.debug('User saved successfully', { userId: user.id.value });
    } catch (error) {
      await client.query('ROLLBACK');
      this.logger.error('Failed to save user', { error, userId: user.id.value });
      throw new RepositoryError('Failed to save user', error);
    } finally {
      client.release();
    }
  }
  
  async delete(id: UserId): Promise<void> {
    const client = await this.db.getClient();
    
    try {
      await client.query('BEGIN');
      
      // 软删除
      const query = `
        UPDATE users 
        SET deleted_at = NOW(), updated_at = NOW()
        WHERE id = $1 AND deleted_at IS NULL
      `;
      
      const result = await client.query(query, [id.value]);
      
      if (result.rowCount === 0) {
        throw new NotFoundError('User not found');
      }
      
      await client.query('COMMIT');
      
      // 清除缓存
      const cacheKey = `user:${id.value}`;
      await this.cache.delete(cacheKey);
      
      this.logger.debug('User deleted successfully', { userId: id.value });
    } catch (error) {
      await client.query('ROLLBACK');
      this.logger.error('Failed to delete user', { error, userId: id.value });
      throw new RepositoryError('Failed to delete user', error);
    } finally {
      client.release();
    }
  }
  
  async findAll(criteria?: UserSearchCriteria): Promise<User[]> {
    try {
      const { query, params } = this.buildSearchQuery(criteria);
      const result = await this.db.query(query, params);
      
      return result.rows.map(row => {
        const userData = this.mapRowToUserData(row);
        return User.fromPersistence(userData);
      });
    } catch (error) {
      this.logger.error('Failed to find users', { error, criteria });
      throw new RepositoryError('Failed to find users', error);
    }
  }
  
  async count(criteria?: UserSearchCriteria): Promise<number> {
    try {
      const { query, params } = this.buildCountQuery(criteria);
      const result = await this.db.query(query, params);
      
      return parseInt(result.rows[0].count, 10);
    } catch (error) {
      this.logger.error('Failed to count users', { error, criteria });
      throw new RepositoryError('Failed to count users', error);
    }
  }
  
  private async insertUser(client: DatabaseClient, userData: UserPersistenceData): Promise<void> {
    // 插入用户基本信息
    const userQuery = `
      INSERT INTO users (id, email, status, created_at, updated_at)
      VALUES ($1, $2, $3, $4, $5)
    `;
    
    await client.query(userQuery, [
      userData.id,
      userData.email,
      userData.status,
      userData.createdAt,
      userData.updatedAt
    ]);
    
    // 插入用户档案
    const profileQuery = `
      INSERT INTO user_profiles (user_id, first_name, last_name, hashed_password, avatar_url)
      VALUES ($1, $2, $3, $4, $5)
    `;
    
    await client.query(profileQuery, [
      userData.id,
      userData.profile.firstName,
      userData.profile.lastName,
      userData.profile.hashedPassword,
      userData.profile.avatarUrl
    ]);
  }
  
  private async updateUser(client: DatabaseClient, userData: UserPersistenceData): Promise<void> {
    // 更新用户基本信息
    const userQuery = `
      UPDATE users 
      SET email = $2, status = $3, updated_at = $4
      WHERE id = $1
    `;
    
    await client.query(userQuery, [
      userData.id,
      userData.email,
      userData.status,
      userData.updatedAt
    ]);
    
    // 更新用户档案
    const profileQuery = `
      UPDATE user_profiles 
      SET first_name = $2, last_name = $3, hashed_password = $4, avatar_url = $5
      WHERE user_id = $1
    `;
    
    await client.query(profileQuery, [
      userData.id,
      userData.profile.firstName,
      userData.profile.lastName,
      userData.profile.hashedPassword,
      userData.profile.avatarUrl
    ]);
  }
  
  private buildSearchQuery(criteria?: UserSearchCriteria): { query: string; params: any[] } {
    let query = `
      SELECT u.*, p.first_name, p.last_name, p.hashed_password, p.avatar_url
      FROM users u
      LEFT JOIN user_profiles p ON u.id = p.user_id
      WHERE u.deleted_at IS NULL
    `;
    
    const params: any[] = [];
    let paramIndex = 1;
    
    if (criteria?.status) {
      query += ` AND u.status = $${paramIndex}`;
      params.push(criteria.status.value);
      paramIndex++;
    }
    
    if (criteria?.emailDomain) {
      query += ` AND u.email LIKE $${paramIndex}`;
      params.push(`%@${criteria.emailDomain}`);
      paramIndex++;
    }
    
    if (criteria?.createdAfter) {
      query += ` AND u.created_at >= $${paramIndex}`;
      params.push(criteria.createdAfter.toISOString());
      paramIndex++;
    }
    
    if (criteria?.createdBefore) {
      query += ` AND u.created_at <= $${paramIndex}`;
      params.push(criteria.createdBefore.toISOString());
      paramIndex++;
    }
    
    query += ' ORDER BY u.created_at DESC';
    
    if (criteria?.limit) {
      query += ` LIMIT $${paramIndex}`;
      params.push(criteria.limit);
      paramIndex++;
    }
    
    if (criteria?.offset) {
      query += ` OFFSET $${paramIndex}`;
      params.push(criteria.offset);
      paramIndex++;
    }
    
    return { query, params };
  }
  
  private buildCountQuery(criteria?: UserSearchCriteria): { query: string; params: any[] } {
    let query = `
      SELECT COUNT(*) as count
      FROM users u
      WHERE u.deleted_at IS NULL
    `;
    
    const params: any[] = [];
    let paramIndex = 1;
    
    if (criteria?.status) {
      query += ` AND u.status = $${paramIndex}`;
      params.push(criteria.status.value);
      paramIndex++;
    }
    
    if (criteria?.emailDomain) {
      query += ` AND u.email LIKE $${paramIndex}`;
      params.push(`%@${criteria.emailDomain}`);
      paramIndex++;
    }
    
    if (criteria?.createdAfter) {
      query += ` AND u.created_at >= $${paramIndex}`;
      params.push(criteria.createdAfter.toISOString());
      paramIndex++;
    }
    
    if (criteria?.createdBefore) {
      query += ` AND u.created_at <= $${paramIndex}`;
      params.push(criteria.createdBefore.toISOString());
      paramIndex++;
    }
    
    return { query, params };
  }
  
  private mapRowToUserData(row: any): UserPersistenceData {
    return {
      id: row.id,
      email: row.email,
      status: row.status,
      profile: {
        firstName: row.first_name,
        lastName: row.last_name,
        hashedPassword: row.hashed_password,
        avatarUrl: row.avatar_url
      },
      createdAt: row.created_at,
      updatedAt: row.updated_at
    };
  }
}

本章练习

  1. SOLID原则

    • 重构现有代码以遵循SOLID原则
    • 识别和修复违反原则的代码
    • 设计符合原则的新功能
  2. 领域驱动设计

    • 设计领域模型和值对象
    • 实现聚合根和领域服务
    • 定义和处理领域事件
  3. 微服务架构

    • 设计服务拆分策略
    • 实现服务间通信
    • 处理分布式事务
  4. 数据访问层

    • 实现Repository模式
    • 设计缓存策略
    • 优化数据库查询

本章总结

本章介绍了企业级TypeScript应用开发的核心概念:

  1. 架构设计原则:SOLID原则和领域驱动设计
  2. 微服务架构:服务拆分和通信策略
  3. 数据访问层:Repository模式和缓存设计
  4. 最佳实践:代码组织和错误处理

下一章将介绍TypeScript的最新特性和未来发展趋势。