HarmonyOS应用<趣答>开发第09篇:服务层架构设计与单例模式——构建可复用的业务逻辑层
·

📖 引言
在知识问答学习应用中,服务层是连接数据层和展示层的关键桥梁。服务层负责封装业务逻辑,提供统一的接口供上层调用,同时保证数据的一致性和安全性。
本文将详细讲解服务层的架构设计,包括单例模式的实现、服务的职责划分、依赖注入等核心内容。通过本文,你将掌握:
- 如何设计可复用的服务层架构
- 如何实现单例模式保证服务唯一性
- 如何划分服务职责
- 如何在实际项目中管理服务依赖
🎯 学习目标
完成本文后,你将能够:
- ✅ 理解服务层的架构设计原则
- ✅ 掌握单例模式的实现方法
- ✅ 设计合理的服务职责划分
- ✅ 实现服务之间的依赖管理
💡 需求分析
功能模块设计
| 模块 | 功能描述 | 技术要点 |
|---|---|---|
| 服务层架构 | 设计服务层的整体架构 | 分层架构、职责分离 |
| 单例模式 | 保证服务实例唯一性 | 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. 服务层架构图
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;
}
工作流程:
- 第一次调用
getInstance()时,创建新实例 - 后续调用返回已创建的实例
- 直接
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. 服务依赖关系图
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 用户服务实现详解
- 📚 介绍用户登录、注册、数据管理等功能
- 🏷️ 探索用户数据的增删改查操作
🔗 相关链接
- 项目源码: Atomgit仓库
💡 提示: 建议结合项目源码阅读,动手实践效果更好!
更多推荐

所有评论(0)