Table of Contents
在Directus用抽象工厂模式建造一个模块化的无头CMS
现代内容管理要求灵活性、可扩展性和清晰的区分关注。 当与 Directus [ 合作时, 一个无头的CMS, 将直观的API层于任何 SQL 数据库上时, 开发者可以建立高度适应性的内容系统。 实现这种模块化的最有效的设计模式之一是 Abstract Fact Fact Factory Pattle 。 这个模式允许您创建相关的对象(内容组件、数据转换器或API响应格式) 家族, 而无需硬编码其混凝土类。 在Directus 生态系统中, 它允许您交换基于用户背景、 本地或特征标记的内容表达逻辑、数据水分化策略,甚至整个“内容家族 ” 。
在无标题背景下理解抽象厂模式
抽象工厂模式提供了创建关联或依赖对象家族的界面。在像WordPress这样的传统CMS中,这可能会控制块或主题。在Directus中,该模式自然地翻译为生成集合、字段配置、API响应形状或前端组件。您不是直接将代码与特定的Directus集合或项目结构相配合,而是定义了生产可互换模块的抽象工厂。当您拥有多个“内容家族”时,例如不同的客户门户、多租位设置或白标签安装,这种模式就会变得强大。
在 Directus 插件或扩展中应用模式
Directus 允许自定义扩展( hoks, endpoint, board, module) 。 抽象工厂模式完全适合这些扩展。 您可以定义一个基于配置或用户角色的厂房, 将正确的控制器、 序列器和字段验证器集即时化。 这可以促进各版本或部署的松散的组合和更容易的维护 。
步骤1:定义内容组件的抽象接口
首先为您厂家将生成的对象创建 TypeScript 或 JavaScript 接口。 对于 Directus 端点插件, 这可能是数据演示对象 :
// Interface for a content renderer used in an API response
interface ContentRenderer {
render(item: Record<string, any>): Record<string, any>;
}
// Interface for a field formatter
interface FieldFormatter {
format(value: any, field: string): any;
}
步骤2:为具体内容家庭实施具体类别
开发具体类别,针对不同用途的情况执行这些接口——例如,“博客”渲染与“产品目录”渲染:
class BlogContentRenderer implements ContentRenderer {
render(item: Record<string, any>): Record<string, any> {
return {
title: item.title,
excerpt: item.excerpt,
date: item.date_created,
body: this.sanitizeHtml(item.body)
};
}
private sanitizeHtml(html: string): string {
return html.replace(/<script[^>]*>.*?<\/script>/gi, '');
}
}
class ProductCatalogRenderer implements ContentRenderer {
render(item: Record<string, any>): Record<string, any> {
return {
name: item.title,
price: item.price,
image: item.image,
inStock: item.quantity > 0
};
}
}
在直径扩展中创建抽象工厂
工厂界面宣布创建每种内容组件( 提交、 提交、 认证等) 的方法。 混凝土工厂将这些物体的家族一起生产 。
工厂界面示例
interface ContentModuleFactory {
createRenderer(): ContentRenderer;
createFormatter(): FieldFormatter;
createValidator(): ItemValidator;
}
具体工厂的博客模块
class BlogModuleFactory implements ContentModuleFactory {
createRenderer(): ContentRenderer {
return new BlogContentRenderer();
}
createFormatter(): FieldFormatter {
return new BlogFieldFormatter(); // formats dates, slugs, etc.
}
createValidator(): ItemValidator {
return new BlogItemValidator(); // ensures required fields for posts
}
}
将工厂并入直达终点
随着工厂的建立,现在可以建立一个Directus自定义终点,根据查询参数或环境变量使用适当的家族:
export default (router, { services, database }) => {
const { ItemsService } = services;
router.get('/content/:module', async (req, res) => {
const module = req.params.module;
let factory: ContentModuleFactory;
switch (module) {
case 'blog':
factory = new BlogModuleFactory();
break;
case 'products':
factory = new ProductModuleFactory();
break;
default:
factory = new DefaultModuleFactory();
}
const renderer = factory.createRenderer();
const validator = factory.createValidator();
const itemsService = new ItemsService(module, { database });
const items = await itemsService.readByQuery({ limit: 20 });
// Validate and render each item
const result = items.map(item => renderer.render(validator.process(item)));
res.json({ data: result });
});
};
高级用途:多租户
Directus 擅长多版本化或访问过滤器。您可以使用抽象工厂模式,根据请求的租户身份来装入不同的工厂配置。每个租户可能拥有自己的一套场面覆盖、嵌入式渲染逻辑,甚至不同的Directus收集结构。工厂将所有这些变化包罗在一起,同时保持您的端点代码清洁和可测试性。
直接的抽象工厂模式的好处
- 灵活性: 在内容家族(blog,catalog,tormet)之间切换,而不重写核心逻辑.
- 保有性: 每个家庭都是孤立的;一个的改变不影响另一个家庭.
- 可扩展性: 添加新的内容家族意味着实施一个新的混凝土工厂及其等级——对现有工厂或消费者没有变化.
- 检验性: 工厂及其产品可独立进行单位测试,提高代码质量。
- 清分离: 模式执行单一责任原则,使您的Directus扩展更便于理解. 更多了解抽象工厂模式.
Directus 开发者的实际考虑
虽然“抽象工厂模式”增加了前置结构,但随着Directus项目的增长,它还是会有所回报。从一个简单工厂开始,供一两个内容家庭使用,然后根据需要扩大。请将您的界面保持在最低限度,只声明消费者实际使用的内容。对于TypeScript项目,请利用通用软件在家庭间强制实施类型安全。如果您正在为“行政应用程序”建造“Directus”面板扩展,请考虑利用“抽象工厂”根据用户权限制作不同的字段配置或仪表板部件。
示例: 管理面板部件工厂
在自定义的 Directus 面板中, 您可能拥有汇总不同收藏中的数据的部件。 工厂决定要将哪些部件进行即时处理 :
interface DashboardWidget {
type: string;
props: Record<string, any>;
render(container: HTMLElement): void;
}
class UsersWidget implements DashboardWidget { ... }
class OrdersWidget implements DashboardWidget { ... }
class Factory {
createWidget(type: string): DashboardWidget {
if (type === 'users') return new UsersWidget();
if (type === 'orders') return new OrdersWidget();
throw new Error('Unknown widget type');
}
}
当不使用此模式时
抽象工厂模式不是银弹。 避免它用于简单、 一次性的内容家庭, 或是当您Directus 的图案很少改变时。 Over 工程化的小型扩展, 以及完整的工厂结构, 可能增加不必要的复杂度。 当您预计到多个家庭、 频繁的加成, 或者您需要根据配置在运行时间交换家庭时使用它 。
对于Directus中更深入的无头建筑和设计模式,请检查Directus无头CMS指南和PHP执行实例[](可适应Node.js).
结论
将抽象工厂模式融入到你的Directus开发过程中,可以形成一个更有条理、适应性更强、更可扩展的无头型CMS。 它鼓励清洁的代码架构,为未来的扩展做准备,并在不牺牲可维护性的情况下利用Directus的灵活性。 通过抽象工厂将内容家庭脱钩,你可以在最小的中断情况下,与你的商业要求一起演化出自己的CMS。