用控制反转设计一个多文件类型配置加载器类


Design a multi file type config loader class with Inversion of Control

假设我有一个加载和解析配置文件的类。但是,该配置文件可以是3种类型:

    JSON
  • YAML
  • INI

如何设计我的"configLoader"为了保持东西:

  1. 松散耦合的
  2. 易于单元测试
  3. 易于切换组件(例如,将旧解析器更改为新的更好的解析器)

但同时:

  1. 易于扩展(我指的是添加新类型的可接受文件,例如XML)
  2. 没有广泛的构造函数或设置器,以使类工作

  • 所有解析器实现相同的接口(ParserInterface)
  • 可以作为知名解析器(如Symfony/Yaml)的包装器(适配器),例如
  • 这个类在DI容器初始化之前被初始化(在逻辑中,这里加载的值实际上会被注入到DI容器中),所以在这里使用它不是一个选项

<标题> 代码

到目前为止我写的是:

class Loader
{
    /**
     * Loads a configuration string from a ConfigFile
     * 
     * @param ConfigFile $configFile
     * @throws ConfigException if the file type is not recognised
     * @return Config ArrayObject with configuration settings
     */
    public function loadFromFile(ConfigFile $configFile)
    {
        // Finds out what type of config file it is
        $type = $configFile->getType();
        //Loads the file into memory
        $configString = $configFile->read();
        
        switch ($type) {
            case ConfigFile::TYPE_YAML:
                $parser = new YAML'YamlParser(); //Here's the problem
                break;
            
            case ConfigFile::TYPE_JSON:
                $parser = new JSON'JsonParser(); //Here's the problem
                break;
            // (...) same for other file types
            
            // Default case if file type is not recognised
            default:
                throw new ConfigException('Config File type not recognised');
        }
        return $parser->decode($configString);
    }
}

如何:

interface ParserInterface{
  public static test(ConfigFile $configFile);
  // other required methods
}

你的加载器方法:

$classes = get_declared_classes();
foreach($classes as $class){
  $class = new 'ReflectionClass($class);
  if(!$class->implementsInterface('ParserInterface'))
    continue;
  $parser = $class->getName();
  if(!$parser::test($configFile))
    continue;
  $parser = $class->newInstance();
  return $parser->decode(...);
}  
throw new Exception(...);

你刚刚"反转控制"的点,配置文件本身决定什么解析器得到使用

我会做很多像Symfony配置组件。实际上,我可能会直接用它