您现在的位置是:网站首页 > 持续集成中的设计模式保障文章详情

持续集成中的设计模式保障

持续集成(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 环境上下文

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步