You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于依赖注入的C#文本编辑器代码重构咨询

问题1:带必填构造参数的DocumentObject生成方案

优先采用工厂模式结合依赖注入的实现,既集中管理解析规则,又能灵活处理必填参数与外部依赖:

  1. 定义基础结构

    • 先明确DocumentObject基类,仅保留数据属性(如匹配到的文本、位置信息),不包含创建逻辑:
      from abc import ABC
      import re
      
      class DocumentObject(ABC):
          def __init__(self, match: re.Match):
              self.match = match
              self.raw_content = match.group(0)
              self.start_pos = match.start()
              self.end_pos = match.end()
      
    • 各子类继承基类,根据自身需求添加属性,构造函数强制传入match:
      class VariableDO(DocumentObject):
          def __init__(self, match: re.Match):
              super().__init__(match)
              self.var_name = match.group(1)
      
      class ScriptDO(DocumentObject):
          def __init__(self, match: re.Match, script_executor):
              super().__init__(match)
              self.script_code = match.group(1)
              self.script_executor = script_executor  # 外部依赖通过DI注入
      
      class DbCallDO(DocumentObject):
          def __init__(self, match: re.Match, db_connection_pool):
              super().__init__(match)
              self.query = match.group(1)
              self.db_pool = db_connection_pool
      
  2. 实现工厂类

    • 工厂类通过依赖注入获取外部服务(如脚本执行器、数据库连接池),同时维护正则表达式→对象创建逻辑的映射表:
      class DocumentObjectFactory:
          def __init__(self, script_executor=None, db_connection_pool=None):
              self.script_executor = script_executor
              self.db_pool = db_connection_pool
              # 定义匹配规则与创建函数的映射
              self.type_mappings = [
                  (re.compile(r"\${(\w+)}"), self._create_variable),
                  (re.compile(r"```python(.*?)```", re.DOTALL), self._create_script),
                  (re.compile(r"{{db:(.*?)}}"), self._create_db_call),
              ]
      
          def _create_variable(self, match: re.Match):
              return VariableDO(match)
      
          def _create_script(self, match: re.Match):
              return ScriptDO(match, self.script_executor)
      
          def _create_db_call(self, match: re.Match):
              return DbCallDO(match, self.db_pool)
      
          def parse(self, text: str) -> list[DocumentObject]:
              """解析文本生成所有DocumentObject"""
              objects = []
              for pattern, creator in self.type_mappings:
                  for match in pattern.finditer(text):
                      objects.append(creator(match))
              # 按位置排序,避免替换时顺序混乱
              return sorted(objects, key=lambda x: x.start_pos)
      
  3. 优势说明

    • 集中管理所有解析规则,新增DocumentObject类型只需在映射表中添加一行,符合开闭原则;
    • 必填参数match直接传递,外部依赖(如脚本执行器)通过构造注入,避免硬编码;
    • 工厂类承担创建逻辑,DocumentObject子类仅负责数据存储,职责单一。
问题2:文档替换逻辑的实现位置

优先选择服务/处理器类实现执行逻辑,而非在DocumentObject中添加Execute方法,核心原因是贴合单一职责原则与长期维护需求:

  1. 处理器模式的实现

    • 定义处理器接口,统一执行入口:
      from abc import ABC, abstractmethod
      
      class IDocumentProcessor(ABC):
          @abstractmethod
          def execute(self, doc_obj: DocumentObject, original_text: str) -> str:
              """执行替换逻辑,返回替换后的文本片段或完整内容"""
              pass
      
    • 为每种DocumentObject实现对应的处理器,注入所需外部服务:
      class VariableProcessor(IDocumentProcessor):
          def __init__(self, variable_store):
              self.variable_store = variable_store
      
          def execute(self, doc_obj: VariableDO, original_text: str) -> str:
              # 变量替换逻辑
              return original_text[:doc_obj.start_pos] + self.variable_store.get(doc_obj.var_name) + original_text[doc_obj.end_pos:]
      
      class ScriptProcessor(IDocumentProcessor):
          def __init__(self, script_executor):
              self.script_executor = script_executor
      
          def execute(self, doc_obj: ScriptDO, original_text: str) -> str:
              # 脚本执行并替换逻辑
              script_result = self.script_executor.run(doc_obj.script_code)
              return original_text[:doc_obj.start_pos] + str(script_result) + original_text[doc_obj.end_pos:]
      
      class DbCallProcessor(IDocumentProcessor):
          def __init__(self, db_connection_pool):
              self.db_pool = db_connection_pool
      
          def execute(self, doc_obj: DbCallDO, original_text: str) -> str:
              # 数据库查询并替换逻辑
              with self.db_pool.get_connection() as conn:
                  result = conn.execute(doc_obj.query).fetchall()
              return original_text[:doc_obj.start_pos] + str(result) + original_text[doc_obj.end_pos:]
      
    • 再实现一个调度器,根据DocumentObject类型匹配对应的处理器:
      class DocumentExecutionScheduler:
          def __init__(self):
              self.processors = {
                  VariableDO: VariableProcessor(variable_store),
                  ScriptDO: ScriptProcessor(script_executor),
                  DbCallDO: DbCallProcessor(db_pool)
              }
      
          def execute_all(self, doc_objects: list[DocumentObject], original_text: str) -> str:
              current_text = original_text
              # 按逆序执行(避免替换后位置偏移)
              for doc_obj in reversed(sorted(doc_objects, key=lambda x: x.start_pos)):
                  processor = self.processors[type(doc_obj)]
                  current_text = processor.execute(doc_obj, current_text)
              return current_text
      
  2. 为什么不选DocumentObject内置Execute

    • 违反单一职责:DocumentObject本应是数据载体,内置执行逻辑会让它同时承担数据存储与业务处理职责,代码耦合度高;
    • 依赖管理困难:执行逻辑往往依赖外部服务(如数据库、脚本引擎),放在DocumentObject中会导致这些依赖被硬编码到实体类,难以测试和替换;
    • 扩展性差:新增DocumentObject类型时,需要修改基类或子类,而处理器模式只需新增处理器类,无需改动原有实体代码。
  3. 特殊情况的折中

    • 如果某些DocumentObject的执行逻辑极其简单(如静态文本替换),可以在基类中添加一个默认的execute方法作为兜底,但仍建议核心逻辑用处理器实现,保持一致性。

内容的提问来源于stack exchange,提问作者iomismo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 18:24:04