通過之前的七個章節(jié),我們已經創(chuàng)建了一個以博客作為示例的完整功能的增刪改查應用程序。在我們制作的過程中應用了幾種不同的設計模式和最佳實踐?,F在是時候來重新數一數并且看看其中一些我們寫過的代碼示例了。這將會以問與答的形式呈現。
簡單回答:不是。
詳細回答:接口的重要性會隨著你的應用程序的增長而增長。如果你可以預見到你的應用程序會被其他人使用并且是可擴展的,那么你應該好好地考慮一下編碼時總是使用接口。這是非常常見的最佳實踐,而且和 ZF2 沒有直接關系,更多的是遵守嚴格的面向對象程序編程規(guī)范。
我們介紹過的多層架構(控制器 -> 服務 -> 映射器 -> 后端)的用處在于讓我們嚴格地分開考慮所有的對象。有許多可用的資源可以為您詳細解釋每一個分層的巨大優(yōu)勢,所以請自行參閱。
然而,對于十分簡單的應用程序,你很可能會將映射器層刪減掉。實際上所有映射器的代碼層通常都直接存放在服務內部。而且這招對大多數應用程序都好使,但一旦你開始打算支持多個后端(例如開源軟件);又或者,你想準備好更換后端,那么你應該總是考慮是否要包含這一層。
簡單回答:沒錯。
詳細回答:實際上沒必要詳細回答。大多數代碼重疊也都來自于映射器層、如果你自己看看那些類,你就會注意到實際上只有兩件事情是和某個具體對象捆綁的。第一件就是,數據庫表的名稱;第二件就是,事實上是對象原型會被傳值給映射器。
原型已經從 __construct()
函數傳進類里所以它已經是可替換的。如果你想讓表名也是可替換的話,你只需要在構造器中提供表名即可,然后你就有了一個全能的數據庫映射器實現,基本上可以用來處理你的應用程序里幾乎所有的對象。
你可以參照下例來編寫一個 factory 類:
<?php
class NewsMapperFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
return new ZendDbSqlMapper(
$serviceLocator->get('Zend\Db\Adapter\Adapter'), // 數據庫適配器
'news', // 表名
new ClassMethods(false), // 對象充水器
new News() // 對象原型
);
}
}
如果你回過頭去看幾年前的代碼示例,就會發(fā)現曾經在每個控制器里面都有大量的代碼。這已經被認為是一個不良實踐,這類控制器被稱為“肥胖控制器”或者“臃腫控制器”。
我們之前創(chuàng)建的每個控制器之間的主要區(qū)別是不同的控制器有不同的依賴對象。舉例來說,WriteController
要求 PostForm
和 PostService
,然而 DeleteController
只要求 PostService
。對于這個例子來說,將 deleteAction()
寫入 WriteController
是不合理的,因為這會導致過程中創(chuàng)建一個不必要的 PostForm
實例。在大型程序中這種錯誤會制造巨大的性能瓶頸,從而拖慢應用程序。
再看看 DeleteController
和 ListController
,你會注意到兩個控制器都有一樣的依賴對象。兩者都只要求 PostService
,那么為何不將其合并成一個控制器呢?原因是語義,你會跑去 ListController
尋找 deleteAction()
嗎?我們大多數人不會干這事,所以我們?yōu)槠浣⒘艘粋€新類。
在應用程序中的 InsertForm
和 UpdateForm
互有區(qū)別,你也許會總是想將其分為兩個控制器而不是像我們的例子中將其做成一個聯合的 WriteController
。這類事情基本上是因應用程序的不同而不同,不過基本目標一直都是:讓你的控制器總是纖細/輕量。
如果你覺得這個 FAQ 還少了點什么,請將你的問題私信給我們,然后我們會給你答案!