Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 正确使用工厂方法/模式和动态加载_Php_Oop_Design Patterns - Fatal编程技术网

Php 正确使用工厂方法/模式和动态加载

Php 正确使用工厂方法/模式和动态加载,php,oop,design-patterns,Php,Oop,Design Patterns,我创建了一个库来解析不同类型的数据。这就是图书馆的使用方式 $parser = DataParser::factory($text); $data = $parser->parse(); foreach($data as $name=>$datum) echo "name: $name\nData: ".$datum."\n"; 这里,$data是namedatacollection的一个实例。下面是类定义 interface Parsable{ // @retur

我创建了一个库来解析不同类型的数据。这就是图书馆的使用方式

$parser = DataParser::factory($text);
$data = $parser->parse();
foreach($data as $name=>$datum)
    echo "name: $name\nData: ".$datum."\n";
这里,
$data
namedatacollection
的一个实例。下面是类定义

interface Parsable{
    // @returns NamedDataCollection
    function parse();
    // @returns bool. True if it can parse the data.
    function can_parse();
}

class AParser implements Parsable{
    public function parse(){
       $this->check_header();
       $this->check_content();
       $this->parse_content();
       ...
    }
    public function can_parse(){
       $this->check_header();
       $this->check_content();
       ...
    }
}

class BParser implements Parsable{
    public function parse(){
       ...
    }
    public function can_parse(){
       ...
    }
}

class ParserRegistry{
    // @param $dir path where all the parsers are stored
    public function __construct($dir){
    }
    // @returns all the available parsers by scanning files. 
    public function get(){
    }
}

class DataParser{
    public function factory($data){
       $instance = null;
       $pr= new ParserRegistry("/some/path");
       foreach($pr->get() as $pname){
           $rc = new ReflectionClass($pname);
           $instance = $rc->newInstance($data);
           if($instance->can_parse())
               return $instance;
       }
       throw new ParserException("No parser found", 1);
    }
}
这是正确的工厂方法使用

困扰我的一件事是
can\u parse
方法似乎有很多解析器实例只是为了测试它是否能够解析文本而创建的。有没有更好的办法?我知道我可以使用静态方法。但是大多数解析器使用
parse
方法的某些部分(请参见
apaser
定义)。如果我把它设为静态,它就不能使用这些方法


注意:示例代码表示我遵循的模式。但是类名和场景只是示例。为示例提供现成的解决方案并不能解决我真正的问题

一般来说,它看起来是正确的。工厂根据输入生成对象。我不确定是否可以解析()。我认为这个决定应该由工厂做出,而不是委托给特定的对象


看看这里

当您自己编写时,您不想实例化(加载定义)所有解析器类,只是为了找出要使用哪一个,您需要更改设计

首先,我强烈建议您让解析器只进行解析,而不是解析和感知数据。一个目标,一个工作。保持简单

数据类型嗅探(即使用哪个解析器)实际上是在工厂中进行的。对于工厂方法来说,这可能有点过分。即使它需要决定实例化哪个具体的类名,也不能意味着它需要为此封装整个逻辑。而且,这可能会随着时间的推移而改变,因为您将随着时间的推移添加解析器

因此,下一个改进可能是使用工厂方法对象,而不是工厂方法。也就是说,您实例化了工厂,它允许您随着时间的推移用新的工厂类型替换它

你应该能够一步一步地做到这一点

  • 从接口中删除
    can_parse
    方法。如果解析器希望在内部使用它,则将其设置为私有。但它不属于任何具体的
    解析器的接口(强制为抽象)
  • 生成
    DataParser
    和实际的
    ParserFactory
    对象。实例化它并在需要的地方传递它。将
    factory
    方法重命名为
    makeParser
    ,以便更清楚地了解发生了什么
  • 将工厂对象转换为接口,并将类重命名为实现该接口的具体名称
  • 现在,您可以根据需要随时间重新实现
    ParserFactory::makeParser
    方法。如果需要,只需创建一个新的factory对象。如果这种情况经常发生变化,您可能也希望将决策注入工厂,但我会推迟这一步。您现在所做的可能是最好的方法,我首先只会将它移出解析器。例如,针对潜在类列表进行测试,并捕获任何表明解析器无法(成功)解析数据的
    ParseExceptions
    。让你的软件继续工作,只是把东西彼此分开一点。之后,您可以创建第二个工厂对象,该对象以不同的方式工作,您所需要做的只是更改该对象,应用程序的其余部分(读取:所有现有解析器)可以保留,因此不需要更改


    这将使您可以自由地进行实验,这是决定如何实例化(制作)具体解析器的最佳方法。

    目前大约有30个解析器。它很快就会发展到几百个。我将其委托给解析器本身,因为
    can\u parse
    逻辑是特定于对象的。如果这个逻辑后来改变了,我不想改变工厂的方法。看起来我真的错了。这个决定应该由一个子类做出,所以你的问题的答案是你做的是正确的。如果没有更多的细节,就很难对性能进行评论。您可以通过注入策略对象来间接查找匹配的解析器来查找这些对象。这并没有回答您的问题,可能只是告诉您以后如何删除
    can\u parse
    依赖关系。-但是您不应该在解析器中引入太多的逻辑。如果解析失败,他们可以抛出一个解析异常,但除此之外,他们不能说是否可以解析。设置一些元信息,比如内容类型,以便解析器只解析。