您现在的位置是:网站首页 > 持续集成中的设计模式保障文章详情
持续集成中的设计模式保障
陈川
【
JavaScript
】
45244人已围观
11135字
持续集成(CI)已成为现代软件开发的核心实践之一,而设计模式在保障其稳定性和可维护性方面发挥着关键作用。JavaScript 设计模式通过提供可复用的解决方案,帮助开发者在 CI 环境中高效处理常见问题,例如构建流程的抽象、测试隔离、依赖管理等。
工厂模式在构建流程中的应用
工厂模式在 CI 中常用于动态创建构建任务或测试环境。例如,根据不同的分支或提交信息生成对应的构建流程:
class BuildPipelineFactory {
createPipeline(branchType) {
switch (branchType) {
case 'feature':
return new FeatureBranchPipeline();
case 'release':
return new ReleasePipeline();
case 'hotfix':
return new HotfixPipeline();
default:
return new DefaultPipeline();
}
}
}
class FeatureBranchPipeline {
execute() {
return ['lint', 'unit-test', 'build-dev'];
}
}
// CI 配置中使用工厂
const factory = new BuildPipelineFactory();
const pipeline = factory.createPipeline('feature');
runTasks(pipeline.execute());
这种模式使得构建逻辑与具体实现解耦,当需要新增分支类型时只需扩展工厂类。
装饰器模式增强测试能力
装饰器模式可以为测试套件动态添加功能,例如在 CI 中为测试添加日志记录、性能监控等横切关注点:
function withRetry(testFn, maxAttempts = 3) {
return async function(...args) {
let lastError;
for (let i = 0; i < maxAttempts; i++) {
try {
return await testFn(...args);
} catch (error) {
lastError = error;
console.log(`Attempt ${i + 1} failed, retrying...`);
}
}
throw lastError;
};
}
// 原始测试
async function databaseTest() {
// 测试数据库操作
}
// 装饰后的测试
const robustTest = withRetry(databaseTest);
// CI 中运行装饰后的测试
describe('CI Test Suite', () => {
it('should pass with retries', robustTest);
});
观察者模式实现构建通知
观察者模式在 CI 中广泛用于构建状态的通知机制,允许不同系统订阅构建事件:
class BuildNotifier {
constructor() {
this.subscribers = [];
}
subscribe(observer) {
this.subscribers.push(observer);
}
notify(event) {
this.subscribers.forEach(observer => observer.update(event));
}
}
class SlackNotifier {
update(event) {
if (event.status === 'failed') {
postToSlack(`构建失败: ${event.buildId}`);
}
}
}
// CI 中使用
const notifier = new BuildNotifier();
notifier.subscribe(new SlackNotifier());
// 构建完成后
notifier.notify({
status: 'failed',
buildId: '12345',
timestamp: Date.now()
});
策略模式处理多环境部署
CI 中经常需要根据不同环境采用不同的部署策略:
class DeploymentStrategy {
deploy() {
throw new Error('必须实现 deploy 方法');
}
}
class BlueGreenDeployment extends DeploymentStrategy {
deploy() {
// 蓝绿部署逻辑
}
}
class CanaryDeployment extends DeploymentStrategy {
deploy() {
// 金丝雀部署逻辑
}
}
class DeploymentContext {
constructor(strategy) {
this.strategy = strategy;
}
setStrategy(strategy) {
this.strategy = strategy;
}
executeDeployment() {
return this.strategy.deploy();
}
}
// CI 中根据环境选择策略
const context = new DeploymentContext();
if (env === 'production') {
context.setStrategy(new BlueGreenDeployment());
} else {
context.setStrategy(new CanaryDeployment());
}
context.executeDeployment();
单例模式管理共享资源
在并行执行的 CI 任务中,单例模式可以确保共享资源(如数据库连接池)的正确管理:
class DatabaseConnectionPool {
constructor() {
if (!DatabaseConnectionPool.instance) {
this.connections = [];
// 初始化连接池
DatabaseConnectionPool.instance = this;
}
return DatabaseConnectionPool.instance;
}
getConnection() {
// 获取连接逻辑
}
}
// CI 测试任务中使用
const pool1 = new DatabaseConnectionPool();
const pool2 = new DatabaseConnectionPool();
console.log(pool1 === pool2); // true,确保所有测试任务使用同一个连接池
责任链模式处理构建错误
构建过程中的错误处理可以通过责任链模式实现分级处理:
class ErrorHandler {
constructor() {
this.nextHandler = null;
}
setNext(handler) {
this.nextHandler = handler;
return handler;
}
handle(error) {
if (this.nextHandler) {
return this.nextHandler.handle(error);
}
return false;
}
}
class CompilationErrorHandler extends ErrorHandler {
handle(error) {
if (error.type === 'COMPILATION') {
console.log('处理编译错误');
return true;
}
return super.handle(error);
}
}
class TestErrorHandler extends ErrorHandler {
handle(error) {
if (error.type === 'TEST') {
console.log('处理测试失败');
return true;
}
return super.handle(error);
}
}
// CI 中配置责任链
const handlerChain = new CompilationErrorHandler()
.setNext(new TestErrorHandler());
// 处理构建错误
handlerChain.handle({ type: 'TEST' });
代理模式控制构建访问
代理模式可以在 CI 中控制对敏感操作的访问,例如生产环境部署:
class DeploymentService {
deployToProduction() {
console.log('执行生产环境部署');
}
}
class DeploymentProxy {
constructor() {
this.service = new DeploymentService();
}
deployToProduction(branch) {
if (branch !== 'main') {
throw new Error('只有 main 分支可以部署到生产环境');
}
return this.service.deployToProduction();
}
}
// CI 中使用代理
const proxy = new DeploymentProxy();
try {
proxy.deployToProduction('feature-123'); // 抛出错误
} catch (e) {
console.error(e.message);
}
模板方法模式标准化构建流程
模板方法可以定义构建的标准流程,同时允许特定步骤的灵活变化:
abstract class BuildTemplate {
execute() {
this.installDependencies();
this.lintCode();
this.runTests();
this.buildArtifacts();
if (this.shouldDeploy()) {
this.deploy();
}
}
installDependencies() {
console.log('安装依赖...');
}
abstract lintCode();
abstract runTests();
buildArtifacts() {
console.log('构建产物...');
}
shouldDeploy() {
return false;
}
deploy() {
throw new Error('必须实现 deploy 方法');
}
}
class WebAppBuild extends BuildTemplate {
lintCode() {
console.log('运行 ESLint...');
}
runTests() {
console.log('运行 Jest 测试...');
}
shouldDeploy() {
return true;
}
deploy() {
console.log('部署到 S3...');
}
}
// CI 中执行
const build = new WebAppBuild();
build.execute();
状态模式管理构建生命周期
构建过程的不同阶段可以用状态模式来管理:
class BuildState {
constructor(build) {
this.build = build;
}
start() {
throw new Error('必须实现 start 方法');
}
}
class PendingState extends BuildState {
start() {
console.log('从待处理状态开始构建');
this.build.setState(new RunningState(this.build));
}
}
class RunningState extends BuildState {
start() {
console.log('构建已在运行中');
}
complete(success) {
console.log('构建完成');
this.build.setState(
success ? new SuccessState(this.build) : new FailedState(this.build)
);
}
}
class BuildProcess {
constructor() {
this.setState(new PendingState(this));
}
setState(state) {
this.state = state;
}
start() {
this.state.start();
}
complete(success) {
if (this.state.complete) {
this.state.complete(success);
}
}
}
// CI 中使用
const build = new BuildProcess();
build.start();
// 模拟构建完成
setTimeout(() => build.complete(true), 1000);
组合模式构建复杂任务
复杂的 CI 流程可以通过组合模式分解为多个子任务:
class CIJob {
constructor(name) {
this.name = name;
this.children = [];
}
add(job) {
this.children.push(job);
}
async run() {
console.log(`开始任务: ${this.name}`);
for (const child of this.children) {
await child.run();
}
console.log(`完成任务: ${this.name}`);
}
}
class TestJob extends CIJob {
async run() {
await super.run();
console.log(`执行测试: ${this.name}`);
}
}
// 构建复杂 CI 流程
const ciPipeline = new CIJob('主构建流程');
const testStage = new CIJob('测试阶段');
testStage.add(new TestJob('单元测试'));
testStage.add(new TestJob('集成测试'));
ciPipeline.add(new CIJob('安装依赖'));
ciPipeline.add(testStage);
ciPipeline.add(new CIJob('构建产物'));
// 执行整个流程
ciPipeline.run();
备忘录模式实现构建回滚
CI 中的部署过程可以使用备忘录模式实现回滚能力:
class DeploymentMemento {
constructor(version) {
this.version = version;
this.timestamp = Date.now();
}
}
class DeploymentOriginator {
constructor() {
this.currentVersion = null;
}
deploy(version) {
console.log(`部署版本: ${version}`);
this.currentVersion = version;
return new DeploymentMemento(version);
}
restore(memento) {
console.log(`回滚到版本: ${memento.version}`);
this.currentVersion = memento.version;
}
}
class DeploymentCaretaker {
constructor() {
this.mementos = [];
}
addMemento(memento) {
this.mementos.push(memento);
}
getMemento(index) {
return this.mementos[index];
}
}
// CI 中使用
const deployer = new DeploymentOriginator();
const caretaker = new DeploymentCaretaker();
// 首次部署
caretaker.addMemento(deployer.deploy('1.0.0'));
// 新版本部署
caretaker.addMemento(deployer.deploy('1.1.0'));
// 出现问题需要回滚
deployer.restore(caretaker.getMemento(0));
适配器模式集成不同工具
CI 中经常需要集成不同工具,适配器模式可以统一接口:
class NewTestFramework {
executeTests() {
return new Promise(resolve => {
console.log('使用新测试框架运行测试');
resolve({ passed: 18, failed: 2 });
});
}
}
class OldTestFramework {
run() {
return {
success: 15,
errors: 1
};
}
}
class TestFrameworkAdapter {
constructor(framework) {
this.framework = framework;
}
async executeTests() {
if (this.framework.executeTests) {
return await this.framework.executeTests();
} else {
const result = this.framework.run();
return {
passed: result.success,
failed: result.errors
};
}
}
}
// CI 中统一调用
async function runAllTests() {
const frameworks = [
new TestFrameworkAdapter(new NewTestFramework()),
new TestFrameworkAdapter(new OldTestFramework())
];
for (const framework of frameworks) {
const result = await framework.executeTests();
console.log(`测试结果: ${result.passed}通过, ${result.failed}失败`);
}
}
runAllTests();
命令模式实现可撤销操作
CI 中的某些操作可能需要撤销功能,命令模式可以提供这种能力:
class DeploymentCommand {
constructor(execute, undo) {
this.execute = execute;
this.undo = undo;
this.executed = false;
}
invoke() {
if (!this.executed) {
this.execute();
this.executed = true;
}
}
revoke() {
if (this.executed) {
this.undo();
this.executed = false;
}
}
}
class CICommandManager {
constructor() {
this.commands = [];
}
invoke(command) {
command.invoke();
this.commands.push(command);
}
rollback() {
while (this.commands.length > 0) {
const command = this.commands.pop();
command.revoke();
}
}
}
// CI 中使用
const manager = new CICommandManager();
const deployCommand = new DeploymentCommand(
() => console.log('部署到生产环境'),
() => console.log('从生产环境回滚')
);
manager.invoke(deployCommand);
// 出现问题需要回滚
manager.rollback();
享元模式优化资源使用
CI 中运行大量测试时,享元模式可以共享测试上下文等资源:
class TestContext {
constructor(environment) {
this.environment = environment;
}
setup() {
console.log(`设置测试环境: ${this.environment}`);
}
}
class TestContextFactory {
constructor() {
this.contexts = {};
}
getContext(environment) {
if (!this.contexts[environment]) {
this.contexts[environment] = new TestContext(environment);
}
return this.contexts[environment];
}
}
// CI 中运行测试
const factory = new TestContextFactory();
function runTest(testName, environment) {
const context = factory.getContext(environment);
context.setup();
console.log(`运行测试: ${testName}`);
}
// 多个测试共享同一个环境上下文
runTest('登录测试', 'staging');
runTest('支付测试', 'staging'); // 复用 staging 环境上下文
上一篇: 自动化测试中的模式验证
下一篇: WebAssembly对设计模式的影响