PHP OOP:接口与非接口方法 - 示例

时间:2012-03-07 16:06:45

标签: php oop interface polymorphism

可以使用不同的工具完成同样的事情。 我在下面的例子中也是如此。

一个显示了interface / polymorphism的使用(来源:nettuts - 我认为)。另一个简单的类交互(我的) - 它也显示了一些多态性(通过call_tool())。

你能告诉我,你认为哪种方式更好。

哪个更安全,更稳定,防篡改,面向未来(关注代码开发)。

请仔细检查两者中使用的范围/可见性。

您的一般建议,这是最好的编码实践。

INTERFACE:

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

2 个答案:

答案 0 :(得分:2)

嗯,无论什么版本,你的方法都有一些缺陷。首先,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,所以你可以返回动态而不关心,但这会带来性能损失,如果返回的类型没有调用该方法,则会抛出异常)

答案 1 :(得分:1)

我会通过推荐this video以及系列中的其他视频开始整个过程​​。

有两个条件可以使接口变得更好:

  • 您正在团队中工作
  • 长期项目

当您需要扩展代码库的功能时,使用接口就像另一组文档一样。此外,还使用了principle of least astonishment

在一个非常小的&amp;快速项目使用接口毫无意义。