2012-03-07 103 views
5

可以使用不同的工具完成同樣的事情。 所以我在下面的例子。PHP OOP:接口與非接口方法 - 示例

一個顯示使用接口/多態(來源:nettuts - 我認爲)。另一個直接的類交互(我的) - 它也顯示了一些多態(通過call_tool())。

你能告訴我,你認爲哪種方式更好?

哪個更安全,更穩定,防篡改,未來的證明(關於afa代碼開發)。

請仔細檢查兩者中使用的範圍/可見性。

您的一般建議,這是最好的編碼實踐。

接口:

 
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

咳咳,你的方法有一定的缺陷,不管是什麼版本。首先,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); 
} 
} 

方法似乎並不雖然被需要的,你只需告訴筆者直接寫入對象。

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

哪個更安全,更穩定,防篡改,未來的證明(關於afa代碼開發)。

這隻取決於開發者的技能和紀律。在這種情況下particualr,我寫的代碼是安全的,防篡改,面向未來:P

更新 事實上,我忘了把干將在poly_base_Article,我現在他們加入。由於你在做序列化,所以文章不應該知道它,因爲它不是他的責任(它是基礎結構層的一部分),所以寫入方法根本不需要,但這是一個特定的情況(在一切取決於在上下文中)。

WriterFactory基本上是工廠模式,它創建了作者的一個實例,並返回一個抽象 - 這是接口有用的多態。這種方法使得添加接口的新實現變得非常容易,並且防止代碼注入。交換機將檢查只允許$ type的有效值。您可以在其他地方驗證$類型,但這是唯一應該處理與創建作者有關的所有內容的地方。即使你想在外部驗證,你也可以在WriterFactory中創建一個靜態方法,它將返回true/false並使用than。

關於接口是一種時尚......使用接口是如何完成OOP的。對抽象進行編程是最佳實踐,接口是最好的抽象。說穿了:如果接口是一種時尚,那麼OOP是一種時尚。

關於第二個例子,以及第一個例子,創建作者的方法不應該在那裏,因爲它將作者的創作與文章耦合在一起,而這兩者幾乎沒有任何共同之處。這是打破SRP(單一責任原則)。

在這種特殊情況下,一旦你在一個單獨的類中創建工廠,那麼你幾乎不關心接口,但是因爲這裏的用法非常簡單,而且你使用PHP或者鬆散地類型語言。如果您將作者作爲依賴關係傳遞,那麼它將有助於傳遞接口而不是實際的實現(就像您在第一個示例中那樣)。知道你傳遞的是什麼類型是非常有幫助的。另外在像C#這樣的語言中,你將會有一個返回類型,然後,作爲一個最佳用法,你可以將它作爲接口類型返回(C#支持動態類型,讓我們說它的行爲有點類似於PHP,所以你可以返回動態和不在意,但是帶有性能損失,如果返回的類型沒有調用該方法將拋出異常)

+0

$ _GET - 那真的不是q的一部分。 ;),所以我沒有太多注意。在實時代碼中,它將從各個角度進行適當的觀察。但是你是對的,我不應該讓它通過,即使這是沒有問題的。範圍。 – Jeffz 2012-03-07 21:18:47

+0

如果您將poly_base_Article屬性設爲私有,如何poly_writer_xmlWriter訪問它們?他們之間沒有任何關係 – Jeffz 2012-03-07 21:31:17

+0

WriterFactory - 是不是隻是創建附加的對象沒有太多的功能添加它呢? – Jeffz 2012-03-07 21:34:08

1

我會開始推薦this video和其他系列視頻。

有兩個條件這將使接口可取:

  • 你在一個團隊中工作
  • 長期項目

使用的界面就像另一組文檔,當你需要擴展你的代碼庫的功能。此外,還使用principle of least astonishment

在一個非常小的&快速項目中,沒有意義使用接口。

+0

我在任何需要抽象的地方使用接口,無論項目的複雜程度如何 – MikeSW 2012-03-08 10:07:26