返回首页 Zend Framework 2 深入学习指南

回顾博客应用程序

通过之前的七个章节,我们已经创建了一个以博客作为示例的完整功能的增删改查应用程序。在我们制作的过程中应用了几种不同的设计模式和最佳实践。现在是时候来重新数一数并且看看其中一些我们写过的代码示例了。这将会以问与答的形式呈现。

我们总是需要所有的层和接口吗?

简单回答:不是。

详细回答:接口的重要性会随着你的应用程序的增长而增长。如果你可以预见到你的应用程序会被其他人使用并且是可扩展的,那么你应该好好地考虑一下编码时总是使用接口。这是非常常见的最佳实践,而且和 ZF2 没有直接关系,更多的是遵守严格的面向对象程序编程规范。

我们介绍过的多层架构(控制器 -> 服务 -> 映射器 -> 后端)的用处在于让我们严格地分开考虑所有的对象。有许多可用的资源可以为您详细解释每一个分层的巨大优势,所以请自行参阅。

然而,对于十分简单的应用程序,你很可能会将映射器层删减掉。实际上所有映射器的代码层通常都直接存放在服务内部。而且这招对大多数应用程序都好使,但一旦你开始打算支持多个后端(例如开源软件);又或者,你想准备好更换后端,那么你应该总是考虑是否要包含这一层。

有这么多对象,难道就不会有很多代码重叠吗?

简单回答:没错。

详细回答:实际上没必要详细回答。大多数代码重叠也都来自于映射器层、如果你自己看看那些类,你就会注意到实际上只有两件事情是和某个具体对象捆绑的。第一件就是,数据库表的名称;第二件就是,事实上是对象原型会被传值给映射器。

原型已经从 __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()                                       // 对象原型
         );
     }
 }

为什么有那么多控制器?

如果你回过头去看几年前的代码示例,就会发现曾经在每个控制器里面都有大量的代码。这已经被认为是一个不良实践,这类控制器被称为“肥胖控制器”或者“臃肿控制器”。

我们之前创建的每个控制器之间的主要区别是不同的控制器有不同的依赖对象。举例来说,WriteController 要求 PostFormPostService,然而 DeleteController 只要求 PostService。对于这个例子来说,将 deleteAction() 写入 WriteController 是不合理的,因为这会导致过程中创建一个不必要的 PostForm 实例。在大型程序中这种错误会制造巨大的性能瓶颈,从而拖慢应用程序。

再看看 DeleteControllerListController,你会注意到两个控制器都有一样的依赖对象。两者都只要求 PostService,那么为何不将其合并成一个控制器呢?原因是语义,你会跑去 ListController 寻找 deleteAction() 吗?我们大多数人不会干这事,所以我们为其建立了一个新类。

在应用程序中的 InsertFormUpdateForm 互有区别,你也许会总是想将其分为两个控制器而不是像我们的例子中将其做成一个联合的 WriteController。这类事情基本上是因应用程序的不同而不同,不过基本目标一直都是:让你的控制器总是纤细/轻量

还有更多的问题吗? 请联络我们!

如果你觉得这个 FAQ 还少了点什么,请将你的问题私信给我们,然后我们会给你答案!