应用程序结构指南
本指南提供了使用 Contexify 构建应用程序结构的建议。
概述
结构良好的应用程序更易于维护、测试和扩展。Contexify 提供了创建模块化和灵活的应用程序结构的工具。
推荐的应用程序结构
以下是使用 Contexify 的典型应用程序的推荐结构:
src/
├── application.ts # 主应用程序类
├── index.ts # 入口点
├── components/ # 可重用组件
│ ├── authentication/ # 认证组件
│ │ ├── index.ts # 组件导出
│ │ ├── keys.ts # 绑定键
│ │ ├── types.ts # 类型定义
│ │ ├── services/ # 服务
│ │ └── providers/ # 提供者
│ └── ... # 其他组件
├── controllers/ # 控制器
│ ├── index.ts # 控制器导出
│ ├── user-controller.ts # 用户控制器
│ └── ... # 其他控制器
├── models/ # 领域模型
│ ├── index.ts # 模型导出
│ ├── user.model.ts # 用户模型
│ └── ... # 其他模型
├── repositories/ # 数据访问仓库
│ ├── index.ts # 仓库导出
│ ├── user.repository.ts # 用户仓库
│ └── ... # 其他仓库
├── services/ # 业务逻辑服务
│ ├── index.ts # 服务导出
│ ├── user.service.ts # 用户服务
│ └── ... # 其他服务
└── config/ # 配置
├── index.ts # 配置导出
├── keys.ts # 绑定键
└── types.ts # 类型定义
应用程序类
应用程序类是应用程序的核心。它扩展了 Context
类,并作为应用程序的根上下文。
import { Context, createBindingFromClass } from 'contexify';
import { UserController } from './controllers';
import { UserService } from './services';
import { UserRepository } from './repositories';
import { AuthComponent } from './components/authentication';
export class MyApplication extends Context {
constructor() {
super('application');
// Configure the application
this.configure();
}
private configure() {
// Register components
this.component(new AuthComponent());
// Register services
this.bind('services.UserService').toClass(UserService);
// Register repositories
this.bind('repositories.UserRepository').toClass(UserRepository);
// Register controllers
this.bind('controllers.UserController').toClass(UserController);
}
// Add a component to the application
component(component: { bindings?: any[] }) {
if (component.bindings) {
for (const binding of component.bindings) {
this.add(binding);
}
}
return this;
}
// Start the application
async start() {
console.log('Application starting...');
// Application startup logic
}
// Stop the application
async stop() {
console.log('Application stopping...');
// Application cleanup logic
this.close();
}
}
组件
组件是可以在应用程序之间重用的相关绑定的集合。它们是组织代码和促进模块化的好方法。
import { createBindingFromClass } from 'contexify';
import { AuthService } from './services';
import { TokenProvider } from './providers';
export class AuthComponent {
bindings = [
createBindingFromClass(AuthService),
createBindingFromClass(TokenProvider),
];
}
控制器
控制器处理传入的请求并返回响应。它们通常依赖于服务来执行业务逻辑。
import { injectable, inject } from 'contexify';
import { UserService } from '../services';
import { User } from '../models';
@injectable()
export class UserController {
constructor(
@inject('services.UserService') private userService: UserService
) {}
async getUser(id: string): Promise<User> {
return this.userService.getUser(id);
}
async createUser(userData: Partial<User>): Promise<User> {
return this.userService.createUser(userData);
}
}
服务
服务包含应用程序的业务逻辑。它们通常依赖于仓库来访问数据。
import { injectable, inject } from 'contexify';
import { UserRepository } from '../repositories';
import { User } from '../models';
@injectable()
export class UserService {
constructor(
@inject('repositories.UserRepository') private userRepo: UserRepository
) {}
async getUser(id: string): Promise<User> {
return this.userRepo.findById(id);
}
async createUser(userData: Partial<User>): Promise<User> {
// Business logic
return this.userRepo.create(userData);
}
}
仓库
仓库处理数据访问。它们通常依赖于数据源来连接数据库。
import { injectable, inject } from 'contexify';
import { DataSource } from '../config';
import { User } from '../models';
@injectable()
export class UserRepository {
constructor(
@inject('datasources.default') private dataSource: DataSource
) {}
async findById(id: string): Promise<User> {
// Data access logic
return this.dataSource.findById('users', id);
}
async create(userData: Partial<User>): Promise<User> {
// Data access logic
return this.dataSource.create('users', userData);
}
}
配置
配置存储在上下文中,可以被服务和其他组件访问。
import { Context } from 'contexify';
// Configuration keys
export namespace ConfigKeys {
export const DATABASE = 'config.database';
export const SERVER = 'config.server';
}
// Configuration types
export interface DatabaseConfig {
host: string;
port: number;
username: string;
password: string;
database: string;
}
export interface ServerConfig {
port: number;
host: string;
}
// Configure the application
export function configureApplication(app: Context) {
// Database configuration
app.bind(ConfigKeys.DATABASE).to({
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT || '5432'),
username: process.env.DB_USER || 'postgres',
password: process.env.DB_PASSWORD || 'postgres',
database: process.env.DB_NAME || 'myapp',
});
// Server configuration
app.bind(ConfigKeys.SERVER).to({
port: parseInt(process.env.PORT || '3000'),
host: process.env.HOST || 'localhost',
});
}
入口点
应用程序的入口点创建并启动应用程序。
import { MyApplication } from './application';
import { configureApplication } from './config';
async function main() {
// Create the application
const app = new MyApplication();
// Configure the application
configureApplication(app);
// Start the application
await app.start();
console.log('Application is running');
// Handle shutdown
process.on('SIGINT', async () => {
console.log('Shutting down...');
await app.stop();
process.exit(0);
});
}
main().catch(err => {
console.error('Failed to start application:', err);
process.exit(1);
});
最佳实践
- 关注点分离:保持应用程序的不同部分分离(控制器、服务、仓库)
- 依赖注入:使用依赖注入使代码更易于测试和维护
- 基于组件的架构:将相关功能组织到组件中
- 配置管理:使用上下文管理配置
- 绑定命名约定:对绑定键使用一致的命名约定
- 错误处理:在整个应用程序中实现适当的错误处理
- 生命周期管理:正确管理应用程序及其组件的生命周期
下一步
现在您已经了解了如何构建应用程序,可以了解: