在这里插入图片描述

📖 引言

在知识问答学习应用中,服务层是连接数据层和展示层的关键桥梁。服务层负责封装业务逻辑,提供统一的接口供上层调用,同时保证数据的一致性和安全性。

本文将详细讲解服务层的架构设计,包括单例模式的实现、服务的职责划分、依赖注入等核心内容。通过本文,你将掌握:

  • 如何设计可复用的服务层架构
  • 如何实现单例模式保证服务唯一性
  • 如何划分服务职责
  • 如何在实际项目中管理服务依赖

🎯 学习目标

完成本文后,你将能够:

  • ✅ 理解服务层的架构设计原则
  • ✅ 掌握单例模式的实现方法
  • ✅ 设计合理的服务职责划分
  • ✅ 实现服务之间的依赖管理

💡 需求分析

功能模块设计

模块 功能描述 技术要点
服务层架构 设计服务层的整体架构 分层架构、职责分离
单例模式 保证服务实例唯一性 private constructor、getInstance
服务职责划分 划分各服务的职责范围 UserService、QuizService等
依赖管理 管理服务之间的依赖关系 依赖注入、服务定位器

🛠️ 核心实现

步骤1: 服务层架构设计

功能说明

服务层架构采用分层设计,将业务逻辑封装在独立的服务类中,每个服务负责特定的业务领域。

完整代码
// services/index.ts

/**
 * 服务层架构设计
 * 
 * 服务层职责:
 * 1. 封装业务逻辑
 * 2. 提供统一接口
 * 3. 管理数据访问
 * 4. 保证事务一致性
 */

export * from './UserService';
export * from './QuizService';
export * from './LevelService';
export * from './AchievementService';
export * from './QuestionService';
export * from './StatisticsService';

/**
 * 服务注册中心
 */
export const ServiceRegistry = {
  user: () => import('./UserService').then(m => m.UserService.getInstance()),
  quiz: () => import('./QuizService').then(m => m.QuizService.getInstance()),
  level: () => import('./LevelService').then(m => m.LevelService.getInstance()),
  achievement: () => import('./AchievementService').then(m => m.AchievementService.getInstance()),
  question: () => import('./QuestionService').then(m => m.QuestionService.getInstance()),
  statistics: () => import('./StatisticsService').then(m => m.StatisticsService.getInstance())
};

/**
 * 服务定位器模式
 */
export class ServiceLocator {
  private static services = new Map<string, unknown>();

  /**
   * 注册服务
   */
  static register<T>(name: string, service: T): void {
    ServiceLocator.services.set(name, service);
  }

  /**
   * 获取服务
   */
  static get<T>(name: string): T | undefined {
    return ServiceLocator.services.get(name) as T;
  }

  /**
   * 获取所有服务名称
   */
  static getAllServiceNames(): string[] {
    return Array.from(ServiceLocator.services.keys());
  }

  /**
   * 初始化所有服务
   */
  static async initialize(): Promise<void> {
    const services = [
      { name: 'user', provider: () => import('./UserService').then(m => m.UserService.getInstance()) },
      { name: 'quiz', provider: () => import('./QuizService').then(m => m.QuizService.getInstance()) },
      { name: 'level', provider: () => import('./LevelService').then(m => m.LevelService.getInstance()) },
      { name: 'achievement', provider: () => import('./AchievementService').then(m => m.AchievementService.getInstance()) },
      { name: 'question', provider: () => import('./QuestionService').then(m => m.QuestionService.getInstance()) },
      { name: 'statistics', provider: () => import('./StatisticsService').then(m => m.StatisticsService.getInstance()) }
    ];

    for (const { name, provider } of services) {
      const service = await provider();
      ServiceLocator.register(name, service);
    }
  }
}
代码解析

1. 服务层架构图

服务层

UserService

QuizService

LevelService

AchievementService

QuestionService

StatisticsService

展示层 UI

服务层

数据层

本地存储

网络请求

2. 服务职责划分

服务名称 职责描述 核心方法
UserService 用户数据管理 getUser(), updateUser(), login()
QuizService 测验流程管理 startQuiz(), submitAnswer(), finishQuiz()
LevelService 关卡管理 getLevel(), isLevelUnlocked(), getProgress()
AchievementService 成就管理 checkAchievements(), getProgress(), unlock()
QuestionService 题目管理 getQuestions(), searchQuestions(), filter()
StatisticsService 统计分析 getStats(), calculateRanking(), generateReport()

步骤2: 单例模式实现

功能说明

单例模式确保每个服务类只有一个实例,避免重复创建对象,提高性能和内存效率。

完整代码
// services/base/BaseService.ts

/**
 * 服务基类
 * 提供单例模式的基础实现
 */
export abstract class BaseService {
  protected constructor() {
    // 私有构造函数,防止外部实例化
  }

  /**
   * 初始化服务
   * 子类可以重写此方法进行初始化操作
   */
  async initialize(): Promise<void> {
    // 默认实现为空
  }

  /**
   * 销毁服务
   * 子类可以重写此方法进行清理操作
   */
  destroy(): void {
    // 默认实现为空
  }
}

/**
 * 单例服务装饰器
 * @param ServiceClass - 服务类
 */
export function Singleton<T extends new (...args: unknown[]) => BaseService>(
  ServiceClass: T
): T {
  let instance: InstanceType<T> | null = null;

  return class extends ServiceClass {
    constructor(...args: unknown[]) {
      if (instance) {
        return instance as unknown as typeof this;
      }
      super(...args);
      instance = this as unknown as InstanceType<T>;
      return instance as unknown as typeof this;
    }

    /**
     * 获取单例实例
     */
    static getInstance(): InstanceType<T> {
      if (!instance) {
        instance = new ServiceClass() as InstanceType<T>;
      }
      return instance;
    }

    /**
     * 重置单例实例(用于测试)
     */
    static resetInstance(): void {
      instance = null;
    }
  } as T;
}

// 使用示例
@Singleton
export class UserService extends BaseService {
  // ... 服务实现
}
代码解析

1. 单例模式原理

@Singleton
export class UserService extends BaseService {
  private constructor() {
    super();
    // 初始化逻辑
  }

  static getInstance(): UserService {
    // 静态方法返回唯一实例
    // ...
  }
}

原理:

  • 使用 @Singleton 装饰器自动实现单例模式
  • 私有构造函数防止外部实例化
  • getInstance() 静态方法返回唯一实例

优势:

  • 保证服务唯一性
  • 节省内存资源
  • 便于状态管理

2. 装饰器实现

export function Singleton<T extends new (...args: unknown[]) => BaseService>(
  ServiceClass: T
): T {
  let instance: InstanceType<T> | null = null;

  return class extends ServiceClass {
    constructor(...args: unknown[]) {
      if (instance) {
        return instance as unknown as typeof this;
      }
      super(...args);
      instance = this as unknown as InstanceType<T>;
      return instance as unknown as typeof this;
    }

    static getInstance(): InstanceType<T> {
      if (!instance) {
        instance = new ServiceClass() as InstanceType<T>;
      }
      return instance;
    }
  } as T;
}

工作流程:

  1. 第一次调用 getInstance() 时,创建新实例
  2. 后续调用返回已创建的实例
  3. 直接 new 操作也会返回已存在的实例

步骤3: 服务依赖管理

功能说明

服务之间可能存在依赖关系,需要合理管理这些依赖,避免循环依赖和耦合过紧。

完整代码
// services/UserService.ts

import { Singleton } from './base/BaseService';
import { LevelService } from './LevelService';
import { AchievementService } from './AchievementService';
import { StatisticsService } from './StatisticsService';

@Singleton
export class UserService extends BaseService {
  private levelService: LevelService;
  private achievementService: AchievementService;
  private statisticsService: StatisticsService;

  constructor() {
    super();
    // 延迟初始化依赖服务
    this.levelService = LevelService.getInstance();
    this.achievementService = AchievementService.getInstance();
    this.statisticsService = StatisticsService.getInstance();
  }

  /**
   * 用户登录
   */
  async login(username: string, password: string): Promise<boolean> {
    // 登录逻辑
    // ...
    
    // 更新登录日期
    await this.updateLastLoginDate();
    
    // 检查成就
    await this.checkLoginAchievements();
    
    return true;
  }

  /**
   * 更新登录日期
   */
  private async updateLastLoginDate(): Promise<void> {
    // 更新用户最后登录日期
    // ...
  }

  /**
   * 检查登录相关成就
   */
  private async checkLoginAchievements(): Promise<void> {
    // 调用成就服务检查连续登录成就
    await this.achievementService.checkConsecutiveDaysAchievement();
  }

  /**
   * 获取用户进度摘要
   */
  async getUserProgressSummary(userId: string): Promise<UserProgressSummary> {
    const user = await this.getUserById(userId);
    
    // 获取关卡进度
    const levelProgress = await this.levelService.getSubjectProgress(user);
    
    // 获取成就进度
    const achievementProgress = await this.achievementService.getUserAchievementProgress(user);
    
    // 获取统计数据
    const statistics = await this.statisticsService.getUserStatistics(user);
    
    return {
      userId: user.id,
      nickname: user.nickname,
      level: user.level,
      totalScore: user.totalScore,
      levelProgress,
      achievementProgress,
      statistics
    };
  }
}
代码解析

1. 服务依赖关系图

UserService

LevelService

AchievementService

StatisticsService

QuestionService

2. 依赖注入方式

@Singleton
export class UserService extends BaseService {
  private levelService: LevelService;
  
  constructor() {
    super();
    // 通过 getInstance() 获取依赖服务
    this.levelService = LevelService.getInstance();
  }
}

优点:

  • 减少耦合
  • 便于测试(可替换mock服务)
  • 支持延迟加载

注意事项:

  • 避免循环依赖
  • 保持依赖关系清晰
  • 使用服务定位器统一管理

步骤4: 服务接口定义

功能说明

定义服务的统一接口,确保各服务遵循相同的设计规范。

完整代码
// services/interfaces/ServiceInterface.ts

/**
 * 服务接口定义
 */
export interface ServiceInterface {
  /**
   * 服务名称
   */
  readonly name: string;

  /**
   * 初始化服务
   */
  initialize(): Promise<void>;

  /**
   * 销毁服务
   */
  destroy(): void;

  /**
   * 检查服务状态
   */
  getStatus(): ServiceStatus;

  /**
   * 重置服务状态(用于测试)
   */
  reset(): void;
}

/**
 * 服务状态枚举
 */
export enum ServiceStatus {
  INITIALIZING = 'initializing',
  READY = 'ready',
  BUSY = 'busy',
  ERROR = 'error'
}

/**
 * 服务错误类型
 */
export enum ServiceError {
  NOT_INITIALIZED = 'Service not initialized',
  TIMEOUT = 'Service timeout',
  INVALID_PARAMS = 'Invalid parameters',
  NOT_FOUND = 'Resource not found',
  CONFLICT = 'Conflict detected'
}

/**
 * 服务响应类型
 */
export interface ServiceResponse<T> {
  success: boolean;
  data?: T;
  error?: ServiceError;
  message?: string;
  timestamp: number;
}

/**
 * 创建成功响应
 */
export function createSuccessResponse<T>(data: T): ServiceResponse<T> {
  return {
    success: true,
    data,
    timestamp: Date.now()
  };
}

/**
 * 创建错误响应
 */
export function createErrorResponse<T>(error: ServiceError, message?: string): ServiceResponse<T> {
  return {
    success: false,
    error,
    message,
    timestamp: Date.now()
  };
}
代码解析

1. 服务响应格式

// 成功响应
{
  success: true,
  data: { /* 返回数据 */ },
  timestamp: 1699999999999
}

// 错误响应
{
  success: false,
  error: 'NOT_FOUND',
  message: 'User not found',
  timestamp: 1699999999999
}

优势:

  • 统一响应格式
  • 便于错误处理
  • 包含时间戳便于日志追踪

2. 服务状态管理

export enum ServiceStatus {
  INITIALIZING = 'initializing',  // 初始化中
  READY = 'ready',                // 就绪
  BUSY = 'busy',                  // 繁忙
  ERROR = 'error'                 // 出错
}

使用场景:

  • 在UI层显示服务状态
  • 控制服务调用时机
  • 错误处理和重试逻辑

⚠️ 常见问题与解决方案

问题1: 循环依赖导致死锁

现象:
服务A依赖服务B,服务B又依赖服务A,导致初始化死锁。

错误代码:

// ❌ 错误:循环依赖
class ServiceA {
  constructor() {
    this.serviceB = new ServiceB();  // 依赖 B
  }
}

class ServiceB {
  constructor() {
    this.serviceA = new ServiceA();  // 又依赖 A,死循环!
  }
}

正确代码:

// ✅ 正确:使用延迟初始化
@Singleton
class ServiceA extends BaseService {
  private serviceB: ServiceB | null = null;

  getServiceB(): ServiceB {
    if (!this.serviceB) {
      this.serviceB = ServiceB.getInstance();  // 延迟获取
    }
    return this.serviceB;
  }
}

@Singleton
class ServiceB extends BaseService {
  private serviceA: ServiceA | null = null;

  getServiceA(): ServiceA {
    if (!this.serviceA) {
      this.serviceA = ServiceA.getInstance();  // 延迟获取
    }
    return this.serviceA;
  }
}

规则/建议:

  • 使用延迟初始化避免循环依赖
  • 通过 getter 方法获取依赖
  • 在服务定位器中统一管理

问题2: 服务初始化顺序问题

现象:
某个服务依赖的服务尚未初始化,导致调用失败。

错误代码:

// ❌ 错误:没有等待初始化完成
async function startApp() {
  const userService = UserService.getInstance();
  await userService.login('user', 'pass');  // 可能失败
}

正确代码:

// ✅ 正确:使用服务定位器统一初始化
async function startApp() {
  // 初始化所有服务
  await ServiceLocator.initialize();
  
  // 现在可以安全使用
  const userService = ServiceLocator.get<UserService>('user');
  await userService?.login('user', 'pass');
}

规则/建议:

  • 使用服务定位器统一初始化
  • 在应用启动时等待所有服务就绪
  • 添加服务状态检查

问题3: 单例模式测试困难

现象:
单例模式使得单元测试困难,无法隔离测试环境。

错误代码:

// ❌ 错误:没有重置方法
@Singleton
class UserService extends BaseService {
  // ...
}

// 测试中无法重置状态

正确代码:

// ✅ 正确:提供重置方法
@Singleton
class UserService extends BaseService {
  // ...

  static resetInstance(): void {
    // 重置单例实例
    // ...
  }
}

// 测试代码
beforeEach(() => {
  UserService.resetInstance();
});

规则/建议:

  • 提供静态重置方法
  • 在测试前重置状态
  • 使用依赖注入便于替换

问题4: 服务职责不清

现象:
某个服务承担了过多职责,导致代码难以维护。

错误代码:

// ❌ 错误:职责过多
@Singleton
class AllInOneService extends BaseService {
  // 用户管理
  login() {}
  register() {}
  
  // 测验管理
  startQuiz() {}
  finishQuiz() {}
  
  // 数据存储
  saveData() {}
  loadData() {}
}

正确代码:

// ✅ 正确:职责分离
@Singleton
class UserService extends BaseService {
  login() {}
  register() {}
}

@Singleton
class QuizService extends BaseService {
  startQuiz() {}
  finishQuiz() {}
}

@Singleton
class StorageService extends BaseService {
  saveData() {}
  loadData() {}
}

规则/建议:

  • 单一职责原则
  • 每个服务专注于一个业务领域
  • 服务之间通过接口交互

问题5: 服务状态管理缺失

现象:
服务没有状态管理,无法知道服务是否就绪。

错误代码:

// ❌ 错误:没有状态管理
@Singleton
class UserService extends BaseService {
  // 直接调用方法,不知道是否就绪
  login() {}
}

正确代码:

// ✅ 正确:添加状态管理
@Singleton
class UserService extends BaseService {
  private status: ServiceStatus = ServiceStatus.INITIALIZING;

  async initialize(): Promise<void> {
    this.status = ServiceStatus.BUSY;
    // 初始化逻辑...
    await this.loadUserData();
    this.status = ServiceStatus.READY;
  }

  getStatus(): ServiceStatus {
    return this.status;
  }

  async login(username: string, password: string): Promise<boolean> {
    if (this.status !== ServiceStatus.READY) {
      throw new Error('Service not ready');
    }
    // 登录逻辑...
  }
}

规则/建议:

  • 添加状态属性
  • 在调用前检查状态
  • 提供状态查询方法

📝 本章小结

核心知识点

本文详细讲解了服务层架构设计与单例模式,主要包括:

1. 服务层架构设计

  • 分层架构设计原则
  • 服务职责划分(6个核心服务)
  • 服务依赖关系管理

2. 单例模式实现

  • 装饰器实现单例模式
  • 私有构造函数防止外部实例化
  • getInstance() 静态方法返回唯一实例

3. 服务接口定义

  • 统一响应格式
  • 服务状态管理
  • 错误处理机制

最佳实践总结

单例模式

@Singleton
export class UserService extends BaseService {
  private constructor() { super(); }
  
  static getInstance(): UserService {
    return super.getInstance();
  }
}

服务依赖注入

@Singleton
class UserService extends BaseService {
  private levelService: LevelService;
  
  constructor() {
    super();
    this.levelService = LevelService.getInstance();
  }
}

统一响应格式

export interface ServiceResponse<T> {
  success: boolean;
  data?: T;
  error?: ServiceError;
  timestamp: number;
}

服务状态管理

private status: ServiceStatus = ServiceStatus.INITIALIZING;

async initialize(): Promise<void> {
  this.status = ServiceStatus.BUSY;
  // 初始化...
  this.status = ServiceStatus.READY;
}

下一步预告

在下一篇文章中,我们将:

  • 🎨 讲解 UserService 用户服务实现详解
  • 📚 介绍用户登录、注册、数据管理等功能
  • 🏷️ 探索用户数据的增删改查操作

🔗 相关链接


💡 提示: 建议结合项目源码阅读,动手实践效果更好!

Logo

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

更多推荐