ZBLOG

在KV存储项目中,随着引擎的越来越多,switch/case也会越来越长。应该使用什么设计模式

在KV存储项目中,随着引擎类型的增加,使用switch/case或长串的if-else来处理不同引擎的逻辑会导致代码臃肿、难以维护。以下是几种适合的设计模式及其实现方式:


1. 工厂模式(Factory Pattern)

  • 核心思想:将引擎对象的创建逻辑封装到工厂类中,通过统一的接口创建不同引擎实例。

  • 适用场景:需要动态选择或扩展多种引擎类型。

  • 实现示例

     class KVEngine {
     public:
         virtual void Put(const std::string& key, const std::string& value) = 0;
         virtual std::string Get(const std::string& key) = 0;
     };
    
    
     class RocksDBEngine : public KVEngine { /*...*/ };
     class LevelDBEngine : public KVEngine { /*...*/ };
    
    
     class KVEngineFactory {
     public:
         static std::unique_ptr<KVEngine> Create(EngineType type) {
             switch (type) {
                 case EngineType::RocksDB: return std::make_unique<RocksDBEngine>();
                 case EngineType::LevelDB: return std::make_unique<LevelDBEngine>();
                 default: throw std::invalid_argument("Unknown engine type");
             }
         }
     };
    
    
     // 使用
     auto engine = KVEngineFactory::Create(EngineType::RocksDB);
    

2. 抽象工厂模式(Abstract Factory Pattern)

  • 核心思想:为引擎族(如基于磁盘的、内存的、分布式的)提供统一的创建接口。
  • 适用场景:需要支持多类引擎族,且每族有多个子类。
  • 优势:避免在客户端代码中硬编码具体引擎类型。

3. 策略模式(Strategy Pattern)

  • 核心思想:将每种引擎的实现封装成独立的策略类,运行时动态切换。

  • 适用场景:需要在运行时灵活切换不同引擎的行为。

  • 实现示例

     class IKVStrategy {
     public:
         virtual void ExecutePut(const std::string& key, const std::string& value) = 0;
     };
    
    
     class RocksDBStrategy : public IKVStrategy { /*...*/ };
    
    
     class KVStore {
         std::unique_ptr<IKVStrategy> strategy_;
     public:
         void SetStrategy(std::unique_ptr<IKVStrategy> strategy) {
             strategy_ = std::move(strategy);
         }
         void Put(const std::string& key, const std::string& value) {
             strategy_->ExecutePut(key, value);
         }
     };
    

4. 注册表模式(Registry Pattern)

  • 核心思想:通过全局注册表动态绑定引擎名称与创建函数,避免硬编码switch/case

  • 适用场景:支持插件化或动态加载新引擎。

  • 实现示例

     using EngineCreator = std::function<std::unique_ptr<KVEngine>()>;
    
    
     class EngineRegistry {
         std::unordered_map<std::string, EngineCreator> creators_;
    
    
        public:
            void Register(const string& name, EngineCreator creator) { 
                creators_[name] = creator; 
            }
    
    
            auto Create(const string& name) { 
                return creators_.at(name)(); 
            }
        };
    
    
        // 注册引擎
        registry.Register("rocksdb", []() { return make_unique<RocksDBEngine>(); });
    
    
        // 使用
        auto engine = registry.Create("rocksdb");
    

5. 依赖注入(Dependency Injection)

结合框架(如Google Guice或手动注入),将具体引擎实例从外部注入,解耦调用方与实现。


选择建议:

  1. 固定/少量引擎类型 → 工厂模式足够。
  2. 需运行时动态切换行为 → 策略模式。
  3. 支持插件化/动态扩展 → 注册表模式 + 配置文件。

通过以上模式可以消除冗长的switch/case,提升代码的可扩展性和可维护性。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=23971

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?