MCP(Model-Controller-Provider模式)是对传统MVC模式的改进版本,更适合现代应用开发。这种分层架构使得代码结构清晰,便于维护和扩展,同时也提高了代码的可测试性和可重用性。每一层都有其明确的职责,通过依赖注入的方式来管理它们之间的关系,使得系统更加灵活和可维护。
- Model:数据模型层,定义数据结构和业务实体Controller:控制层,处理用户输入并协调Model和ProviderProvider:提供者层,负责数据访问和业务逻辑的实现
主要优势:
- 解耦:各层职责明确,相互独立可测试:每层都可以独立测试可维护:修改某一层不影响其他层可扩展:易于添加新功能和修改现有功能依赖清晰:通过依赖注入管理组件关系
以一个电商系统的订单管理模块为例,详细说明MCP (Model-Controller-Provider)模式的应用:
- 整体架构关系图:
┌─────────────────┐
│ HTTP请求 │
└────────┬────────┘
↓
┌─────────────────┐
│ 路由配置层 │ 路由将请求映射到对应的Controller方法
│ (Routes) │
└────────┬────────┘
↓
┌─────────────────┐
│ 控制器层 │ 处理HTTP请求/响应,参数验证,调用Provider
│ (Controller) │
└────────┬────────┘
↓
┌─────────────────┐
│ 提供者层 │ 实现核心业务逻辑,操作Model
│ (Provider) │
└────────┬────────┘
↓
┌─────────────────┐
│ 模型层 │ 定义数据结构和实体关系
│ (Model) │
└─────────────────┘
- 数据流向和依赖关系:
// 1. Model层是基础,被其他层引用
interface Order {
id: string;
items: OrderItem[];
// ...其他属性
}
// 2. Provider层依赖Model层,实现业务逻辑
class OrderProvider {
// 使用Model定义的数据结构
async createOrder(data: Order): Promise<Order> {
// 业务逻辑实现
}
}
// 3. Controller层依赖Provider层,处理HTTP请求
class OrderController {
constructor(
private orderProvider: OrderProvider // 依赖注入
) {}
async createOrder(req: Request, res: Response) {
// 调用Provider层的方法
const order = await this.orderProvider.createOrder(req.body);
res.json(order);
}
}
// 4. 依赖注入层组装各个组件
class OrderModule {
static configure() {
// 创建Provider实例
const provider = new OrderProvider();
// 注入Provider到Controller
const controller = new OrderController(provider);
return { controller };
}
}
// 5. 路由配置层连接HTTP请求和Controller
function configureRoutes(app: Express) {
const { controller } = OrderModule.configure();
app.post('/orders', controller.createOrder.bind(controller));
}
- Model层被所有其他层引用,定义数据结构和类型,但不依赖其他层,其数据模型定义是:
// models/order.model.ts
export interface OrderItem {
productId: string;
quantity: number;
price: number;
}
export interface Order {
id: string;
userId: string;
items: OrderItem[];
totalAmount: number;
status: OrderStatus;
createdAt: Date;
updatedAt: Date;
}
export enum OrderStatus {
PENDING = 'PENDING',
PAID = 'PAID',
SHIPPED = 'SHIPPED',
DELIVERED = 'DELIVERED',
CANCELLED = 'CANCELLED'
}
- Provider层依赖Model层,被Controller层调用,用于实现核心业务逻辑,其业务逻辑实现是:
// providers/order.provider.ts
export class OrderProvider {
constructor(
private readonly orderRepository: OrderRepository,
private readonly inventoryProvider: InventoryProvider,
private readonly paymentProvider: PaymentProvider
) {}
async createOrder(userId: string, items: OrderItem[]): Promise<Order> {
// 检查库存
await this.checkInventory(items);
// 计算总金额
const totalAmount = this.calculateTotal(items);
// 创建订单
const order = {
userId,
items,
totalAmount,
status: OrderStatus.PENDING,
createdAt: new Date(),
updatedAt: new Date()
};
return this.orderRepository.save(order);
}
async payOrder(orderId: string, paymentMethod: string): Promise<Order> {
const order = await this.orderRepository.findById(orderId);
// 处理支付
await this.paymentProvider.processPayment({
orderId,
amount: order.totalAmount,
method: paymentMethod
});
// 更新订单状态
order.status = OrderStatus.PAID;
order.updatedAt = new Date();
return this.orderRepository.update(order);
}
private async checkInventory(items: OrderItem[]): Promise<void> {
for (const item of items) {
const available = await this.inventoryProvider.checkStock(item.productId);
if (available < item.quantity) {
throw new Error(`Insufficient stock for product ${item.productId}`);
}
}
}
private calculateTotal(items: OrderItem[]): number {
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
}
- Controller层依赖Provider层,被路由配置调用处理HTTP请求/响应,其请求处理和响应是:
// controllers/order.controller.ts
export class OrderController {
constructor(private readonly orderProvider: OrderProvider) {}
async createOrder(req: Request, res: Response) {
try {
const { userId, items } = req.body;
// 输入验证
this.validateCreateOrderInput(userId, items);
// 调用Provider创建订单
const order = await this.orderProvider.createOrder(userId, items);
// 返回成功响应
res.status(201).json({
success: true,
data: order
});
} catch (error) {
// 错误处理
res.status(400).json({
success: false,
error: error.message
});
}
}
async payOrder(req: Request, res: Response) {
try {
const { orderId, paymentMethod } = req.body;
// 处理支付
const updatedOrder = await this.orderProvider.payOrder(
orderId,
paymentMethod
);
res.status(200).json({
success: true,
data: updatedOrder
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message
});
}
}
private validateCreateOrderInput(userId: string, items: OrderItem[]) {
if (!userId) throw new Error('User ID is required');
if (!items || items.length === 0) throw new Error('Order items are required');
// 更多验证逻辑...
}
}
- 依赖注入和模块组装,用于创建和组装其他层的实例,管理依赖关系,提供模块化配置:
用组装电脑的例子来解释依赖注入的三个核心概念:
- 创建和组装其他层的实例,就像电脑组装店:
- 首先需要采购各种零件:主板、CPU、内存、硬盘等
- 然后按照正确的顺序把这些零件组装到一起
- 确保每个零件都是兼容的,能够正常工作
- 最终组装成一台完整的电脑
- 管理依赖关系,就像电脑零件之间的连接关系:
- CPU必须安装在主板的CPU插槽上
- 内存必须插在主板的内存插槽上
- 显卡需要插在主板的PCIe插槽上
- 每个零件都有其特定的连接方式和依赖关系
- 提供模块化配置,就像根据不同用户需求配置电脑:
- 游戏玩家需要高性能显卡和大容量内存
- 办公用户可能只需要集成显卡和普通内存
- 设计师需要专业显卡和大容量存储
- 可以根据预算和需求灵活调整配置
实际应用的好处:
- 灵活替换
- 就像CPU坏了可以直接更换新的
- 不需要更换其他正常工作的零件
- 只要接口兼容,可以随时升级零件
- 便于维护
- 每个零件都是独立的模块
- 出现问题容易定位是哪个零件的问题
- 维修或更换时不会影响其他零件
- 标准化
- 所有零件都遵循统一的接口标准
- 不同厂商的零件可以互相兼容
- 组装过程有标准的步骤和流程
- 可扩展性
- 需要更多功能时可以添加新的零件
- 可以根据需求升级某些零件
- 系统容易扩展和升级
总结来说,依赖注入就像是一个专业的电脑组装工厂:
- 负责准备和组装所有需要的零件(创建实例)
- 确保零件之间正确连接(管理依赖)
- 根据不同需求提供不同配置(模块化配置)
这种方式让系统像组装电脑一样模块化,容易维护,也更容易根据需求进行调整和升级。
// modules/order.module.ts
export class OrderModule {
static configure() {
const orderRepository = new OrderRepository();
const inventoryProvider = new InventoryProvider();
const paymentProvider = new PaymentProvider();
const orderProvider = new OrderProvider(
orderRepository,
inventoryProvider,
paymentProvider
);
const orderController = new OrderController(orderProvider);
return { orderController };
}
}
- 路由配置依赖Controller层,映射URL到Controller方法,是应用的入口点:
// routes/order.routes.ts
export function configureOrderRoutes(app: Express) {
const { orderController } = OrderModule.configure();
app.post('/api/orders', orderController.createOrder.bind(orderController));
app.post('/api/orders/:id/pay', orderController.payOrder.bind(orderController));
}