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

如何优雅封装多模型类?现有API传递式封装的优化方案咨询

这是个很常见的OOP封装设计问题,我来给你几个实用的方案参考:

方案1:组合模式+动态属性注入(最推荐)

这个方案既能满足你想要的api.Launch(params...)的简洁调用方式,又不会让Api类变得臃肿,同时保持模型类的独立性。

核心思路是:在Api初始化时,动态把独立的模型类和当前API实例绑定,让模型方法自动使用当前API实例,无需手动传递。

示例代码:

class Api:
    def __init__(self, api_key=None, base_url="https://launchlibrary.net/1.4/"):
        self.api_key = api_key
        self.base_url = base_url
        # 动态绑定需要的模型类,注入当前API实例
        self.Launch = self._bind_model(LaunchModel)
        self.Rocket = self._bind_model(RocketModel)
        # 其他模型类同理添加
    
    def _bind_model(self, model_cls):
        # 包装模型类,让它的方法自动使用当前API实例
        class BoundModel(model_cls):
            @classmethod
            def fetch(cls, **params):
                # 调用原模型方法时自动传入当前API实例
                return super().fetch(api=self, **params)
        
        # 保持原模型类的名称,方便调试和使用
        BoundModel.__name__ = model_cls.__name__
        return BoundModel

# 独立的模型类,专注于数据逻辑和API交互
class LaunchModel:
    @classmethod
    def fetch(cls, api, **params):
        # 这里直接使用传入的api实例调用接口
        url = f"{api.base_url}launch"
        # 处理参数、请求逻辑...
        response = requests.get(url, params={**params, "api_key": api.api_key})
        return response.json()

使用方式完全符合你的预期:

import launchlibrary as ll
api = ll.Api(api_key="your_key")
launches = api.Launch.fetch(limit=10)

这个方案的优势:

  • Api类不会被大量模型代码塞满,只负责初始化和绑定逻辑
  • 模型类依然独立,便于单独维护、测试和扩展
  • 用户调用体验简洁,符合直觉
方案2:使用模型基类+API实例注入

如果不想用动态绑定,也可以定义一个模型基类,让所有模型继承它,基类自动持有当前API实例的引用。

示例代码:

class BaseModel:
    _api = None
    
    @classmethod
    def set_api(cls, api):
        cls._api = api
    
    @classmethod
    def get_api(cls):
        if not cls._api:
            raise ValueError("请先初始化Api实例")
        return cls._api

class Api:
    def __init__(self, api_key=None):
        self.api_key = api_key
        # 给所有模型基类设置当前API实例
        BaseModel.set_api(self)
        # 提供快捷访问方式
        self.Launch = LaunchModel
        self.Rocket = RocketModel

class LaunchModel(BaseModel):
    @classmethod
    def fetch(cls, **params):
        api = cls.get_api()
        # 用api实例处理请求...
        pass

这个方案的好处是结构更清晰,模型类通过基类统一获取API实例,缺点是如果同时使用多个Api实例,会存在全局状态冲突的问题,适合单实例场景。

方案3:使用实例化模型(而非类方法)

如果愿意调整调用方式,也可以让模型先和API实例绑定,再调用方法,这样更加符合OOP的实例化逻辑:

class Api:
    def __init__(self, api_key=None):
        self.api_key = api_key
    
    def launch(self):
        return LaunchModel(api=self)

class LaunchModel:
    def __init__(self, api):
        self.api = api
    
    def fetch(self, **params):
        # 使用self.api处理请求...
        pass

使用方式:

api = ll.Api(api_key="your_key")
launches = api.launch().fetch(limit=10)

这个方案的优势是完全符合OOP的实例依赖注入逻辑,每个模型实例都明确持有对应的API实例,适合复杂场景下的多实例管理。

总结

如果优先考虑用户调用的简洁性和代码结构的清爽,方案1是最优选择;如果项目规模不大、单实例场景居多,方案2足够好用;如果追求严格的OOP实例化逻辑,方案3更合适。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:45:29