0

構成ファイルをロードして解析するクラスがあるとします。ただし、その構成ファイルには次の 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);
    }
}
4

2 に答える 2

1

どうですか:

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(...);

そして、構成ファイル自体がどのパーサーを使用するかを決定するところまで「制御を反転」しました。

于 2013-05-12T18:16:32.577 に答える
1

Symfony Config Componentとよく似ています。実際、私はおそらくそれを使用するでしょう。

于 2013-05-12T17:49:38.747 に答える