[英]PHP OOP: interface vs. non-interface approach - examples
可以使用不同的工具完成相同的事情。 我在下面的例子中也是如此。
一个显示了interface / polymorphism的使用(来源:nettuts - 我认为)。 另一个直接的类交互(我的) - 它也显示了一些多态性(通过call_tool())。
你能告诉我,你认为哪种方式更好。
哪个更安全,更稳定,防篡改,面向未来(关注代码开发)。
请仔细检查两者中使用的范围/可见性。
您的一般建议,这是最好的编码实践。
接口:
class poly_base_Article { public $title; public $author; public $date; public $category; public function __construct($title, $author, $date, $category = 0, $type = 'json') { $this->title = $title; $this->author = $author; $this->date = $date; $this->category = $category; $this->type = $type; } public function call_tool() { $class = 'poly_writer_' . $this->type . 'Writer'; if (class_exists($class)) { return new $class; } else { throw new Exception("unsupported format: " . $this->type); } } public function write(poly_writer_Writer $writer) { return $writer->write($this); } } interface poly_writer_Writer { public function write(poly_base_Article $obj); } class poly_writer_xmlWriter implements poly_writer_Writer { public function write(poly_base_Article $obj) { $ret = ''; $ret .= '' . $obj->title . ''; $ret .= '' . $obj->author . ''; $ret .= '' . $obj->date . ''; $ret .= '' . $obj->category . ''; $ret .= ''; return $ret; } } class poly_writer_jsonWriter implements poly_writer_Writer { public function write(poly_base_Article $obj) { $array = array('article' => $obj); return json_encode($array); } } $article = new poly_base_Article('Polymorphism', 'Steve', time(), 0, $_GET['format']); echo $article->write($article->call_tool());
非接口
class npoly_base_Article { public $title; public $author; public $date; public $category; public function __construct($title, $author, $date, $category = 0, $type = 'json') { $this->title = $title; $this->author = $author; $this->date = $date; $this->category = $category; $this->type = $type; //encoding type - default:json } public function call_tool() { //call tool function if exist $class = 'npoly_writer_' . $this->type . 'Writer'; if (class_exists($class)) { $cls = new $class; return $cls->write($this); } else { throw new Exception("unsupported format: " . $this->type); } } } class npoly_writer_jsonWriter { public function write(npoly_base_Article $obj) { $array = array('article' => $obj); return json_encode($array); } } class npoly_writer_xmlWriter { public function write(poly_base_Article $obj) { $ret = ''; $ret .= '' . $obj->title . ''; $ret .= '' . $obj->author . ''; $ret .= '' . $obj->date . ''; $ret .= '' . $obj->category . ''; $ret .= ''; return $ret; } } $article = new npoly_base_Article('nPolymorphism', 'Steve', time(), 0, $_GET['format']); echo$article->call_tool();
MikeSW代码(如果我做对了)
class poly_base_Article { private $title; private $author; private $date; private $category; public function __construct($title, $author, $date, $category = 0) { $this->title = $title; $this->author = $author; $this->date = $date; $this->category = $category; } public function setTitle($title) { return $this->title = $title; } public function getTitle() { return $this->title; } public function getAuthor() { return $this->author; } public function getDate() { return $this->date; } public function getCategory() { return $this->category; } } interface poly_writer_Writer { public function write(poly_base_Article $obj); } class poly_writer_xmlWriter implements poly_writer_Writer { public function write(poly_base_Article $obj) { $ret = ''; $ret .= '' . $obj->getTitle() . ''; $ret .= '' . $obj->getAuthor() . ''; $ret .= '' . $obj->getDate() . ''; $ret .= '' . $obj->getCategory() . ''; $ret .= ''; return $ret; } } class poly_writer_jsonWriter implements poly_writer_Writer { public function write(poly_base_Article $obj) { //array replacement //$obj_array = array('title' => $obj->getTitle(), 'author' => $obj->getAuthor(), 'date' => $obj->getDate(), 'category' => $obj->getCategory()); //$array = array('article' => $obj_array); $array = array('article' => $obj); //$obj arrives empty return json_encode($array); } } class WriterFactory { public static function GetWriter($type='json') { switch ($type) { case 'json': case 'xml': $class = 'poly_writer_' . $type . 'Writer'; return new $class; break; default: throw new Exception("unsupported format: " . $type); } } } $article = new poly_base_Article('nPolymorphism', 'Steve', time(), 0); $writer=WriterFactory::GetWriter($_GET['format']); echo $writer->write($article);
嗯,无论什么版本,你的方法都有一些缺陷。 首先,poly_base_Article暴露了破坏封装的字段,并且首先违背了使用OOP的目的。
接下来,通过$ _GET参数在那里进行精细注入。 这种课程的正确方法应该是这样的
class poly_base_Article {
private $title;
private $author;
private $date;
private $category;
public function __construct($title, $author, $date, $category = 0) {
$this->title = $title;
$this->author = $author;
$this->date = $date;
$this->category = $category;
}
public function getTitle() { return $this->title;}
//...other getters defined here...
public function AsArray()
{
return (array) $this;
}
//this could be removed
public function write(poly_writer_Writer $writer) {
return $writer->write($this);
}
}
看起来似乎并不需要write方法,你只需告诉编写器直接编写对象。
* call_tool *方法应该属于一个服务或作为工厂方法来创建poly_writer_Writer的实例(顺便说一下,你应该更改类的命名和接口更自然的东西),像这样的东西
class WriterFactory
{
public static function GetWriter($type='json')
{
switch($type)
{
case 'json'
case 'xml': $class= 'poly_writer_' . $type . 'Writer';
return new $class;
break;
default: throw new Exception("unsupported format: " . $type);
}
}
}
$article = new poly_base_Article('nPolymorphism', 'Steve', time(), 0);
$writer=WriterFactory::GetWriter(, $_GET['format']);
echo $writer->write($article);
哪个更安全,更稳定,防篡改,面向未来(关注代码开发)。
这仅取决于开发人员的技能和纪律。 在这个特殊情况下,我写的代码是更安全,防篡改和未来的证据:P
更新确实,我忘了把getter放在poly_base_Article中,我现在已经添加了它们。 由于你正在进行序列化,文章不应该知道它,因为它不是他的责任(它是基础设施层的一部分)所以根本不需要写方法,但这是一个特定的情况(在所有的东西中取决于在上下文中)。
WriterFactory基本上是工厂模式,它创建一个writer的实例并返回一个抽象 - 这是接口有用的多态。 这种方法可以很容易地添加接口的新实现,也可以防止代码注入。切换是检查是否只允许$ type的有效值。 您可以在其他地方验证$ type,但这是唯一应该处理与创建编写器相关的内容的地方。 即使你想在它之外进行验证,你只需在WriterFactory中创建一个静态方法,它将返回true / false并使用than。
关于接口是一种时尚...使用接口是如何完成OOP。 对抽象进行编程是最佳实践,接口是“最佳”抽象。 说穿了:如果界面是时尚,那么OOP就是一种时尚。
关于你的第二个例子,也是第一个例子,创建作者的方法不应该首先在那里,因为它将作者的创作与文章结合起来,而那些2几乎没有任何共同之处。 这是SRP(单一责任原则)的突破。
在这种特殊情况下,一旦你在一个单独的类中创建工厂,那么你几乎不关心接口,但是因为这里的用法非常简单,你使用的是PHP或松散类型的语言。 如果您将编写器作为依赖项传递,那么它将有助于传递接口而不是实际的实现(就像您在第一个示例中所做的那样)。 知道你传递的是什么类型是非常有帮助的。
另外在像C#这样的语言中,你会有一个返回类型,然后,作为一种最佳用法,你将它作为接口类型返回(C#支持动态类型,让我们说有点像在PHP中,所以你可以返回动态而不是关心,但这会带来性能损失,如果返回的类型没有调用该方法,它将抛出异常)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.