【问题标题】:Is there a need to abstract services by creating a "container" [closed]是否需要通过创建“容器”来抽象服务 [关闭]
【发布时间】:2015-09-22 10:37:17
【问题描述】:

我目前正在从事一个个人项目,并且我已经实现了服务层。我更喜欢独立存储服务,因此我在一个文件中没有大型库。下面是文件结构的简要示例

    services/
        user/
            authentication
            login
            logout
            registration
        news/
            articles
            article

我认识一些实现userService 类的人,它将对我目前拥有的所有内容进行分组。我更喜欢我的方法来节省未来编辑的时间 + 我有很多用户服务/功能,所以最好把它分开。最近有人建议我在我的服务文件夹的根目录中实现一个userService 类,并使用它来调用/执行应用程序中所需的服务。下面是我的例子/理解

<?php

/**
 *-----------------------------------------------------------------
 * 
 *  USER SERVICE CLASS
 *  
 *  Simplifies Service Usage Within Application 
 * 
 */
namespace Service;
use \Helper\ServiceAccess;

class UserService extends ServiceAccess {

    // Define Service Prefix Key
    protected $prefix = 'user/';
}

///////////////////////////////////////////////////////////////////
// Separate File ( Helper Function )
///////////////////////////////////////////////////////////////////

/**
 *-----------------------------------------------------------------
 *  
 *  SERVICE ACCESS LAYER
 * 
 *  Used to Simplify the Process of Executing Services, and Grouping 
 *  Alerts For Simple Front-end Error Messages
 *  
 */
namespace Helper;

class ServiceAccess extends Base {
    public $dependencies = ['factory'];

    // Default Service Prefix
    protected $prefix = '';

    // Alert Container Used By Controller to Set UI Alerts
    protected $alerts = [
        'errors'    => [],
        'info'      => [],
        'success'   => [],
        'warning'   => []
    ];


    /**
     *  Service Execution Method
     * 
     *  Used Within Parent Service Classes Such as          UserServices
     *                                                      TournamentServices
     *                                                      etc.
     * 
     *  @param string $key          Refers to the Factory Key ( Excluding Prefix )
     *  @param mixed  $input        Any Type of Input to Be Passed to Execute Method of Child Service
     */
    public function execute($key, $input = []) {

        // Create Service Class Via Factory - Call Execute Method Within Service
        $service = $this->factory->make($this->prefix . $key);
        $execute = $service->execute($input);

        // Get & Merge Alerts From Service
        $this->setAlerts($service);

        // Return Result From Service Execution
        return $execute;
    }


    /**
     *  Set Alerts
     * 
     *  @param array $alerts        Front-End User Alerts Defined By Services
     */
    private function setAlerts($service) {
        $this->alerts   = [
            'errors'    => array_merge($this->alerts['errors'],     (array) $service->get('errors')),
            'info'      => array_merge($this->alerts['info'],       (array) $service->get('info')),
            'success'   => array_merge($this->alerts['success'],    (array) $service->get('success')),
            'warning'   => array_merge($this->alerts['warning'],    (array) $service->get('warning'))
        ];
    }
}

控制器示例

<?php

/**
 *-----------------------------------------------------------------
 * 
 *  LOGIN CONTROLLER
 * 
 */
namespace Controller\www;
use \Helper\Controller;

class Login extends Controller {
    public $dependencies = ['arena', 'login', 'notification', 'site', 'userservice'];

    /**
     *  Login
     * 
     *  Login Runs Through Various Checks Including If User is Banned, Account is Locked, 
     *  or Forgot Password Request Is Active. Then the Entered Password is Matched & if Valid
     *  User is Logged In
     */
    public function index() {

        // User Already Logged In Redirect
        $this->user->get('id') ? $this->redirect->home() : '';                                                                  


        /** 
         *  User Login
         * 
         *  If      Successful, Login User, Redirect Home
         *  Else    Set Error Alerts 
         */
        if ($this->form->post('login')) { 

            // Define and Sanitize Post Data
            $input = $this->input->get(['username', 'password']);

            // Execute Login Service Layer - Define Flash Alerts
            $login  = $this->userservice->execute('login', $input);
            $this->alerts($this->userservice->get('alerts'));

            // Redirect Home on Successful Login
            $login === true ? $this->redirect->home() : '';
        }
    }
}

ServiceAccess 类中的 execute 方法是我被建议做的其余部分我为我的用户错误处理添加的。我的问题如下

为什么这比直接在应用程序中调用服务更好? 它简化了我的控制器中的服务/警报设置的执行(在控制器中将大约 15 行代码变成了 4 行)但是我有类似user/transactions(处理用户帐户的贷记/借记)之类的服务,并且它们有单独的方法需要使用。所以我想知道是UserService 类还是我的事务类需要更新。我正在考虑在事务中定义一个执行方法,并在输入中传递一个键来定义正在使用的事务类型。

这是在我的应用程序中访问/实现服务的最佳途径吗?

【问题讨论】:

    标签: php model-view-controller service architecture


    【解决方案1】:

    抽象的目的是管理底层的复杂性。如果系统的整体复杂性因为增加了一层而降低了,那就去做吧。如果不是,请重新考虑。架构中的每一层都应该有一个存在的目的。并且这个目的必须传达(记录)给开发人员,否则每个人都只是在黑暗中刺伤。

    规划架构的一个好方法是绘制架构图并为每一层分配角色。每一层可以是单个类或类的集合。如果您很难为特定层找到一个好的、干净的角色,那么您可能根本不需要该层。

    我知道您在架构中使用了 MVC 模式,但这并不构成整个架构,只是一种广泛的方法。想想你的服务和各个层的消费和执行。想想你的架构中你想要的层。 UserService 类在您的架构中有意义吗?它属于哪一层?那层的作用是什么?有时您需要一个额外的抽象层来减少重复代码 - 就像您在您的案例中似乎已经实现的那样;有时您只是想以简单、直观的方式进行操作,而不是过于复杂。

    每个架构层、每个模式、每个抽象都可以很好地应用或严重滥用。添加这样的层是否会使您或团队中的其他开发人员感到困惑?如果是的话,把它拿出来。每一层(抽象)的应用应该是优雅和直观的——它应该让团队中的其他人都说“哦,是的,这很聪明”。但是,如果您最终遇到开发人员不确定如何扩展/维护代码的情况,就会适得其反。

    没有很好的理解整个应用的意图和开发者(你)的背景,是不可能做出好的选择或者给出好的建议的。因此,虽然我知道您在寻求最佳实践——本质上是“我们应该在我们的架构/框架中应用多少抽象?”,但实际上并没有正确的答案。这取决于太多的事情——包括开发人员的偏好,甚至包括编码风格。有些人甚至会说 MVC 在服务器端是错误的。

    总结:我不能直接给你“是”或“否”的答案。而且我认为没有人可以。对于架构框架,任何人都可以给出的唯一建议是:保持DRY,但避免使用over-engineering

    【讨论】:

    • 谢谢你。我开始以“正确”的方式做事。几个月前,我从意大利面条程序代码切换到了 oop mvc,所以我仍然不确定我解决特定问题的方法是否是正确的方法/方法。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2015-10-27
    • 2020-04-22
    • 1970-01-01
    • 2021-07-01
    • 2010-09-07
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多