您如何使用(父)class 作为其他(子)class 的网关/接口?
How do you use a (parent) class as a gateway / interface to other (child) classes?
假设您有一个名为 'Parser' 的 class,它充当其他 class 的管理器,每个都与不同类型的解析器相关。我希望能够调用主解析器 class 并让它与特定的解析器提供程序交互。
例如:
$response = $this->Parser->setProvider('ParserA')->setTemplate($template)->parse($data);
这就是我目前对主要解析器 class 的看法,但我觉得有更好的方法,我也 运行 遇到了限制:
class Parser
{
private $provider;
public $template;
private function callMethod($provider, $method, $data)
{
$response = false;
$class = 'ServiceProviders\Parser\'.ucfirst($provider);
if(method_exists($class, $method)) {
$classInstance = new $class;
$response = $classInstance->$method($data);
} else {
throw new \Exception('INVALID METHOD: '.$class.'->'.$method);
}
return $response;
}
public function setProvider($provider)
{
$this->provider = $provider;
return $this;
}
public function setTemplate($template)
{
$this->template = $template;
return $this;
}
public function parse($data)
{
$result = null;
try {
$result = $this->callMethod($this->provider, __FUNCTION__, $data);
} catch(\Exception $e) {
throw new \Exception('There was a problem calling the parser: '.$e->getMessage());
}
return $result;
}
}
每个解析器提供程序、ParserA、ParserB 都有解析方法。我在使用这种方法时遇到的问题是 ParserA 需要模板而 ParserB 不需要。
我是强迫症,不想把传递给parse函数的参数变成数组。尽管简单的解决方案是这样做:
$parameters = array('data' => $data, 'template' = null);
callMethod($provider, $method, $parameters);
我想要做的是使用 setTemplate() 方法在主解析器 class 中设置 ParserA 的 $template 值。
我已经尝试了一些方法来做到这一点。我尝试将 Parser class 变成一个接口,但这并没有解决任何问题(或者我不明白)。我尝试让 ParserA 扩展 Parser,但后来我无法调用 ParserA 的特定 parse() 方法,因为它随后成为父类的方法。
有没有办法实现我忽略的这个?
我认为您的方法在这里略有偏差:Parser 是 class 与 ParsingHandler 不同的一种,将两者混为一谈可能无济于事。你的要求是 classic Strategy Pattern 东西。
您的解析器应该提供解析的能力,但它不应该知道进行解析实际需要什么。将其交给 ParsingHandler(在我的示例中,如下所示)。 ParsingHandler 可以做任何它想做的事情,只要它提供了一个 Parser 将调用的方法来进行实际的解析:在我的例子中 parse()
.
这是一个骨架:
class Parser {
private $parsingHandler;
function __construct($parsingHandler){
$this->parsingHandler = $parsingHandler;
}
function parse(){
return $this->parsingHandler->parse();
}
}
class TemplatedParsingHandler {
private $template;
function __construct($template){
$this->template = $template;
}
function parse(){
// use the template when parsing
}
}
class DefaultParsingHandler {
function parse(){
// just parses stuff
}
}
$myTemplatedParsingHandler = new TemplatedParsingHandler($myTemplate);
$myDefaultParsingHandler = new DefaultParsingHandler();
$myTemplatedParser = new Parser($myTemplatedParsingHandler);
$myDefaultParser = new Parser($myDefaultParsingHandler);
$myTemplatdResult = $myTemplatedParser->parse();
$myUntemplatedResult = $myDefaultParser->parse();
所以 TemplatedParsingHandler 知道它需要一个模板,但是 Parser 不需要 知道。这是它的 none 业务:它不取决于 TemplatedParsingHandler 如何进行解析,它只需要知道它的 ParsingHandler 有一个 parse()
方法。
可以使用接口对 ParseHandlers 强制执行最低 parse()
要求,但 PHP 是一种动态语言,因此这有点违背其预期的编码方法。鸭子绑在这里很好。如果你初始化解析器的对象提供了一个 parse()
方法,你不需要比它更明确。
根据此处的评论和对工厂模式的其他研究的见解,我找到了解决我的问题的解决方案。它还提供了一个不使用静态调用的工厂方法。
class Parser
{
private $ParserProvider;
public function __construct( string $provider )
{
$this->ParserProvider = new \ReflectionClass($provider);
}
public function __invoke($data, $template = null)
{
$Parser = $this->ParserProvider->newInstance();
if(isset($template)) {
return $Parser->setTemplate($template)->parse($data);
} else {
return $Parser->parse($data);
}
}
}
并创建一个没有模板的新解析器:
$ParserA = new Parser('ParserA');
$result = $ParserA($contents);
并使用模板创建新的解析器:
$ParserB = new Parser('ParserB');
$result = $ParserB($contents, $template);
假设您有一个名为 'Parser' 的 class,它充当其他 class 的管理器,每个都与不同类型的解析器相关。我希望能够调用主解析器 class 并让它与特定的解析器提供程序交互。
例如:
$response = $this->Parser->setProvider('ParserA')->setTemplate($template)->parse($data);
这就是我目前对主要解析器 class 的看法,但我觉得有更好的方法,我也 运行 遇到了限制:
class Parser
{
private $provider;
public $template;
private function callMethod($provider, $method, $data)
{
$response = false;
$class = 'ServiceProviders\Parser\'.ucfirst($provider);
if(method_exists($class, $method)) {
$classInstance = new $class;
$response = $classInstance->$method($data);
} else {
throw new \Exception('INVALID METHOD: '.$class.'->'.$method);
}
return $response;
}
public function setProvider($provider)
{
$this->provider = $provider;
return $this;
}
public function setTemplate($template)
{
$this->template = $template;
return $this;
}
public function parse($data)
{
$result = null;
try {
$result = $this->callMethod($this->provider, __FUNCTION__, $data);
} catch(\Exception $e) {
throw new \Exception('There was a problem calling the parser: '.$e->getMessage());
}
return $result;
}
}
每个解析器提供程序、ParserA、ParserB 都有解析方法。我在使用这种方法时遇到的问题是 ParserA 需要模板而 ParserB 不需要。
我是强迫症,不想把传递给parse函数的参数变成数组。尽管简单的解决方案是这样做:
$parameters = array('data' => $data, 'template' = null);
callMethod($provider, $method, $parameters);
我想要做的是使用 setTemplate() 方法在主解析器 class 中设置 ParserA 的 $template 值。
我已经尝试了一些方法来做到这一点。我尝试将 Parser class 变成一个接口,但这并没有解决任何问题(或者我不明白)。我尝试让 ParserA 扩展 Parser,但后来我无法调用 ParserA 的特定 parse() 方法,因为它随后成为父类的方法。
有没有办法实现我忽略的这个?
我认为您的方法在这里略有偏差:Parser 是 class 与 ParsingHandler 不同的一种,将两者混为一谈可能无济于事。你的要求是 classic Strategy Pattern 东西。
您的解析器应该提供解析的能力,但它不应该知道进行解析实际需要什么。将其交给 ParsingHandler(在我的示例中,如下所示)。 ParsingHandler 可以做任何它想做的事情,只要它提供了一个 Parser 将调用的方法来进行实际的解析:在我的例子中 parse()
.
这是一个骨架:
class Parser {
private $parsingHandler;
function __construct($parsingHandler){
$this->parsingHandler = $parsingHandler;
}
function parse(){
return $this->parsingHandler->parse();
}
}
class TemplatedParsingHandler {
private $template;
function __construct($template){
$this->template = $template;
}
function parse(){
// use the template when parsing
}
}
class DefaultParsingHandler {
function parse(){
// just parses stuff
}
}
$myTemplatedParsingHandler = new TemplatedParsingHandler($myTemplate);
$myDefaultParsingHandler = new DefaultParsingHandler();
$myTemplatedParser = new Parser($myTemplatedParsingHandler);
$myDefaultParser = new Parser($myDefaultParsingHandler);
$myTemplatdResult = $myTemplatedParser->parse();
$myUntemplatedResult = $myDefaultParser->parse();
所以 TemplatedParsingHandler 知道它需要一个模板,但是 Parser 不需要 知道。这是它的 none 业务:它不取决于 TemplatedParsingHandler 如何进行解析,它只需要知道它的 ParsingHandler 有一个 parse()
方法。
可以使用接口对 ParseHandlers 强制执行最低 parse()
要求,但 PHP 是一种动态语言,因此这有点违背其预期的编码方法。鸭子绑在这里很好。如果你初始化解析器的对象提供了一个 parse()
方法,你不需要比它更明确。
根据此处的评论和对工厂模式的其他研究的见解,我找到了解决我的问题的解决方案。它还提供了一个不使用静态调用的工厂方法。
class Parser
{
private $ParserProvider;
public function __construct( string $provider )
{
$this->ParserProvider = new \ReflectionClass($provider);
}
public function __invoke($data, $template = null)
{
$Parser = $this->ParserProvider->newInstance();
if(isset($template)) {
return $Parser->setTemplate($template)->parse($data);
} else {
return $Parser->parse($data);
}
}
}
并创建一个没有模板的新解析器:
$ParserA = new Parser('ParserA');
$result = $ParserA($contents);
并使用模板创建新的解析器:
$ParserB = new Parser('ParserB');
$result = $ParserB($contents, $template);