15

最近被Jani Hartikainen在讨论如何最好地处理 MVC 应用程序中的表单数据时介绍了服务层。在做了一些阅读之后,我真的可以看到这种方法的好处。我的问题是这样的:

服务类应该如何构建?

  • 首先,user_service()我的模型是合适的类名user()还是有其他标准?
  • 由于我的服务中的方法只会执行一项任务,因此认为这些总是可以是正确的static function吗?服务类不代表数据,而是一系列动作,所以这似乎是合适的。
  • 服务方法是否应该只接受一个argument,这将是一个array

考虑一个表单已将数据发布到控制器以保存用户数据:

<?php

    class form_controller extends controller
    {

        public function process_submit()
        {
            if(user_service::update_preferences($_POST))
            {

                echo json_encode(array('success' => true));
            }
            else
            {
                echo json_encode(array('success' => false));
            }
        }

    }

    class user_service
    {

        // Accepts array()
        public static function update_preferences($fields)
        {

            // Check for required fields
            if((
                isset($fields['firstname']) and
                isset($fields['lastname']) and
                isset($fields['email'])
                ) == false
            {
                return false;
            }

            // Update user
            try
            {
                $s = new user();
                $s->set_firstname($fields['firstname']);
                $s->set_lastname($fields['lastname']);
                $s->set_email($fields['email']);
                $s->update();

                return true;
            }
            catch(Exception $e)
            {
                return false;
            }
        }
    }

我觉得这是一个很好的方法,因为:

  • 我可以在我的表单中添加另一个字段,我不必更新controller,只需更新service. 控制器不应该关心正在传递什么数据,这似乎是正确的,只要它被传递。这使我的控制器很小,并且我的模型中的逻辑。
  • 如果我没有通过array,我可以设置带有多个参数的函数。例如我的功能可能是update_preferences($firstname, $lastname, $email). 然而,这可能会使函数具有超过 20 个参数(对于大型形式),并且使用顺序会变得很糟糕。
  • 我可以通过一个object,但这有意义吗?如果我正在创建一个对象,它应该是它所代表的对象(在这种情况下是用户)对吗?但是控制器实例化用户对象有意义吗?这不是服务层的重点吗?
  • 也许有一些方法有多个参数(当只有一到三个时)和一些接受数组的方法(当有很多字段时)。这似乎是一场噩梦,因为您总是必须引用该类才能知道该特定方法要求什么。

有人对这里的正确做法有意见吗?我在正确的轨道上吗?你过去做了什么?非常感谢!

4

1 回答 1

25

还不如回答这个问题,因为你甚至给我发了一封电子邮件;)

首先, user_service() 是我的 user() 模型的适当类名还是有其他标准?

这是可以接受的。但是,您应该使用已建立的 PHP 编码约定之一,例如 PEAR 或 ZF 约定。在这两种情况下,类名都是UpperCamelCase和方法名lowerCamelCase。使用这个,类将是UserUserService

由于我的服务中的方法只会执行一项任务,因此认为这些始终可以是静态函数是否正确?服务类不代表数据,而是一系列动作,所以这似乎是合适的。

不。使方法静态化是一个糟糕的设计选择——这适用于大多数代码,而不仅仅是服务。服务的主要原因之一是通常您的服务需要与数据存储或代表数据层的另一个类(存储库、数据访问对象等)进行交互。

当您的服务具有静态方法时,这意味着您需要在方法中实例化您的依赖关系。这反过来意味着,除其他外,代码变得难以测试,因为您无法轻松替换依赖项。

例如这里有一些很好的阅读(事实上,该博客上的几乎所有内容对于软件开发人员来说都是很好的阅读)

服务方法是否应该只接受一个参数,即数组?

这取决于方法的作用。假设您处理表单结果集的示例,那么是的,这可能会起作用。在其他情况下,这可能是一个糟糕的选择。

我可以在我的表单中添加另一个字段,我不必更新控制器,只需更新服务。[ ... ]

如果我没有传递数组,我可以设置具有多个参数的函数。[ ... ]

是的,在我看来,您对这两个案例的论证非常适合这个用例。

我可以传递一个对象,但这有意义吗?如果我正在创建一个对象,它应该是它所代表的对象(在这种情况下是用户)对吗?但是控制器实例化用户对象有意义吗?这不是服务层的重点吗?

这取决于。例如,如果您使用的框架允许您将表单表示为对象(例如 Zend Framework 和Zend_Form),您可以考虑将表单对象直接传递给服务。

也许有一些方法有多个参数(当只有一到三个时)和一些接受数组的方法(当有很多字段时)。这似乎是一场噩梦,因为您总是必须引用该类才能知道该特定方法要求什么。

您通常应该根据方法的名称使参数至少可以猜到一半。在我从事的工作中,我们有一个模型,例如企业和产品,企业可以在其中赞助产品。在 aProductService中,我们有一个名为的方法sponsorProduct,它将业务和产品作为参数。你几乎可以猜到这需要这两个(如果你熟悉代码库的话)

IDE 通常也可以帮助您解决此问题 - 它们提供代码辅助,显示参数函数采用的内容。这是我认为 IDE 在大型项目中非常有用的主要原因之一,在这些项目中,您不能总是记住某个函数究竟需要什么作为参数。

至于参数计数,我认为通常您应该尝试使用单独的参数。这使任何人都可以通过查看函数的签名轻松地查看需要哪些参数,并允许您非常轻松地定义类型提示和默认值。

但是,当您获得如此多的参数时,就有些过分了。这可能是 +5 左右,这取决于它是哪种方法。在这种情况下,您可以考虑使用数组或称为参数对象的东西,它本质上是一个包含调用的所有参数的对象。更多关于参数对象here

于 2011-06-29T18:49:43.317 回答