GO的作业工厂模式详解

Go工厂模式实现全景图

调用
被实现
组合复用
被实现
客户端代码
工厂接口
具体工厂
基础结构体
其他工厂

为什么需要工厂模式?

问题场景

假设没有工厂模式:

// 直接根据任务类型硬编码资源生成
func generateResources(taskType string) Resources {
    switch taskType {
    case "k8s-job":
        // 300行生成Job的代码
    case "spark":
        // 500行处理Spark提交的逻辑
    case "flink":
        // 另一个逻辑分支...
    }
}

痛点

  1. 代码臃肿(单个函数上千行)
  2. 修改风险高(牵一发而动全身)
  3. 无法复用校验逻辑
工厂模式优势
优势说明业务价值
隔离变化新增任务类型只需添加新工厂类提升扩展性
逻辑复用校验方法可被所有工厂复用减少重复代码
职责清晰每个工厂只关注自己的领域提升可维护性
易于测试可对单个工厂Mock测试提高质量

一、核心组件定义

1. 工厂接口(契约)
// job/factory.go
type JobFactory interface {
    Validate(ctx context.Context) error          // 参数校验
    GenerateResources(ctx context.Context)      // 资源生成
    GetRuntimeConfig() map[string]interface{}   // 获取配置
}
2. 基础结构体(公共能力)
// job/base_factory.go
type BaseFactory struct {
    task      *TaskInfo      // 公共字段
    subtasks  []*SubTaskInfo
    logger    Logger         // 公共依赖
    metrics   MetricsCollector
}

// 公共方法实现
func (b *BaseFactory) validateCommon() error {
    if len(b.subtasks) == 0 {
        return ErrEmptyTasks
    }
    return nil
}
3. 具体工厂(业务实现)
// job/k8s_factory.go
type KubernetesFactory struct {
    *BaseFactory           // 组合基础能力
    kubeClient *k8s.Client // 特有依赖
}

func (k *KubernetesFactory) Validate(ctx context.Context) error {
    if err := k.validateCommon(); err != nil { // 复用基础校验
        return err
    }
    if k.task.Namespace == "" {
        return ErrMissingNamespace
    }
    return nil
}

二、隐式接口实现机制

实现原理
var _ JobFactory = (*KubernetesFactory)(nil) // 类型检查

// 编译器自动检查:
1. KubernetesFactory 是否实现所有接口方法?
   - Validate() ✔️
   - GenerateResources() ✔️
   - GetRuntimeConfig() ✔️
2. 全部实现 → 满足接口
与传统语言对比
特性Java/C#Go
接口声明class A implements B无显式声明
方法关联显式@Override方法签名匹配即实现
类型检查编译时强制通过var _检查

三、组合模式深度解析

1. 内存结构
k8sFactory := &KubernetesFactory{
    BaseFactory: &BaseFactory{...},
    kubeClient: client,
}

内存布局:

+-----------------------+
| KubernetesFactory     |
|   +----------------+ |
|   | BaseFactory*   |----> 独立的BaseFactory实例
|   +----------------+ |
|   kubeClient*      |----> 指向k8s客户端
+-----------------------+
2. 方法调用链
k8sFactory.validateCommon() 的执行路径:
1. 查找KubernetesFactory是否有该方法 → ❌
2. 查找嵌入的BaseFactory → ✅找到并执行
3. 方法覆盖示例
// 在KubernetesFactory中重写基础方法
func (k *KubernetesFactory) GetRuntimeConfig() map[string]interface{} {
    baseConfig := k.BaseFactory.GetRuntimeConfig() // 调用父级
    baseConfig["k8s_specific"] = true
    return baseConfig
}

四、工厂创建流程

1. 初始化过程
func NewJobFactory(task *TaskInfo) (JobFactory, error) {
    base := &BaseFactory{
        task:     task,
        logger:   NewLogger(),
        metrics:  NewMetrics(),
    }

    switch task.JobType {
    case "k8s":
        client, err := k8s.NewClient(task.ClusterID)
        return &KubernetesFactory{
            BaseFactory: base,
            kubeClient: client,
        }, nil
    case "spark":
        return &SparkFactory{
            BaseFactory: base,
            sparkOpts:   parseSparkConfig(task),
        }, nil
    }
}
2. 生命周期示意图
ClientFactoryBaseK8sNewJobFactory(task)初始化基础结构体创建具体工厂(注入base)返回KubernetesFactoryValidate()validateCommon()校验结果返回错误或继续ClientFactoryBaseK8s

五、设计决策要点

1. 何时使用接口方法 vs 结构体方法
场景推荐方式示例
需要多态调用接口方法factory.Validate()
内部工具方法结构体私有方法(k *K8sFactory) initDeployment()
跨工厂共享逻辑BaseFactory公共方法base.validateCommon()
2. 组合模式最佳实践
  • 避免深层嵌套:通常只组合1-2层
  • 明确职责边界
    // 不好的实践:模糊的责任划分
    type K8sFactory struct {
        *BaseFactory
        *NetworkManager 
        *StorageHelper
    }
    
    // 好的实践:清晰单一职责
    type K8sFactory struct {
        *BaseFactory
        k8sResources *ResourceBuilder // 聚合子模块
    }
    
3. 初始化复杂度管理
// 复杂初始化使用Option模式
type FactoryOption func(*BaseFactory)

func WithCustomLogger(l Logger) FactoryOption {
    return func(b *BaseFactory) {
        b.logger = l
    }
}

func NewBaseFactory(opts ...FactoryOption) *BaseFactory {
    b := &BaseFactory{...} // 默认值
    for _, opt := range opts {
        opt(b)
    }
    return b
}

六、性能优化技巧

1. 对象池复用
var factoryPool = sync.Pool{
    New: func() interface{} {
        return &KubernetesFactory{
            BaseFactory: &BaseFactory{...},
        }
    },
}

func GetFactory() *KubernetesFactory {
    return factoryPool.Get().(*KubernetesFactory)
}

func PutFactory(f *KubernetesFactory) {
    f.ResetState()
    factoryPool.Put(f)
}
2. 并行资源生成
func (k *KubernetesFactory) GenerateResources(ctx context.Context) error {
    var wg sync.WaitGroup
    errChan := make(chan error, 2)

    // 并行生成Deployment
    wg.Add(1)
    go func() {
        defer wg.Done()
        _, err := k.createDeployment()
        errChan <- err
    }()

    // 并行生成Service
    wg.Add(1)
    go func() {
        defer wg.Done()
        _, err := k.createService()
        errChan <- err
    }()

    go func() {
        wg.Wait()
        close(errChan)
    }()

    for err := range errChan {
        if err != nil {
            return err
        }
    }
    return nil
}

七、测试策略

1. 接口Mock测试
type MockFactory struct {
    ValidateFunc func(ctx context.Context) error
}

func (m *MockFactory) Validate(ctx context.Context) error {
    return m.ValidateFunc(ctx)
}

func TestHandler(t *testing.T) {
    mock := &MockFactory{
        ValidateFunc: func(ctx context.Context) error {
            return errors.New("test error")
        }
    }
    
    handler := NewHandler(mock)
    err := handler.Process()
    assert.Error(t, err)
}
2. 表格驱动测试
func TestK8sFactory_Validate(t *testing.T) {
    tests := []struct {
        name    string
        task    *TaskInfo
        wantErr bool
    }{
        {
            name: "valid task",
            task: &TaskInfo{Namespace: "default"},
            wantErr: false,
        },
        {
            name: "empty namespace",
            task: &TaskInfo{Namespace: ""},
            wantErr: true,
        },
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            f := &KubernetesFactory{
                BaseFactory: &BaseFactory{task: tt.task},
            }
            err := f.Validate(context.Background())
            assert.Equal(t, tt.wantErr, err != nil)
        })
    }
}

八、扩展与演进

1. 新增工厂类型流程
定义新结构体
实现接口方法
注册到工厂创建函数
添加专属测试
2. 典型扩展示例
// 新增Flink任务支持
type FlinkFactory struct {
    *BaseFactory
    flinkConfig FlinkConfig
}

func (f *FlinkFactory) GenerateResources() error {
    // 实现Flink集群部署逻辑
}

// 更新工厂创建器
func NewJobFactory(task *TaskInfo) (JobFactory, error) {
    // ...
    case "flink":
        return &FlinkFactory{
            BaseFactory: base,
            flinkConfig: parseFlinkConfig(task),
        }, nil
}

通过这种模式,你的作业系统可以获得:

  • 横向扩展能力:新增任务类型不影响现有逻辑
  • 纵向复用能力:公共逻辑集中在BaseFactory
  • 清晰的架构边界:各工厂类职责单一
  • 可测试性:接口便于Mock测试

关键要记住:Go的工厂模式是通过 接口定义行为 + 结构体组合复用 + 隐式实现验证 这三大支柱实现的,这与传统OOP语言的实现有本质区别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值