是否需要通过创建 "container" 来抽象服务

Is there a need to abstract services by creating a "container"

我目前正在做一个个人项目,我已经实现了服务层。我更喜欢独立存储服务,这样我就不会在一个文件中拥有一个大型库。以下文件结构的简要示例

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

我认识一些人,他们实施了 userService class 将我目前拥有的所有东西组合在一起。我更喜欢我的方法来在以后的编辑中节省时间+我有很多用户services/functionality所以最好把它分开。我最近被建议在我的服务文件夹的根目录中实现 userService class 并将其用于 call/execute 应用程序中所需的服务。下面是我的example/understanding

<?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 class 中的执行方法是我被建议做的其余部分,我为我的用户错误处理添加了。我的问题如下

为什么这比直接在应用程序中调用服务更好? 它简化了我控制器中 services/setting 警报的执行(将 ~15 行代码变成了控制器中的 4 行)但是我有像 user/transactions 这样的服务(处理 credit/debit 用户帐户)他们有不同的方法需要使用。所以我想知道是 UserService Class 还是我的交易 class 需要更新。我正在考虑在交易中定义一个执行方法,并在输入中传递一个键来定义正在使用的交易类型。

这是在我的应用程序中处理 accessing/implementing 服务的最佳途径吗?

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

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

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

每个架构层、每个模式、每个抽象都可以被很好地应用或被严重滥用。添加这样一个层会让您或团队中的其他开发人员感到困惑吗?如果有,请将其取出。每一层(抽象)的应用都应该是优雅和直观的——它应该让团队中的其他人都去 "Oh yea, this is smart." 但是如果你最终遇到开发人员不确定如何 extend/maintain 代码的情况,它会适得其反。

没有很好地了解整个应用程序的意图和开发人员(您)的背景,就不可能做出好的选择或给出好的建议。因此,虽然我知道您要求的是最佳实践 - 本质上 "how much abstraction should we apply in our architecture/framework?",但确实没有正确答案。这取决于太多东西——开发人员的偏好,甚至包括编码风格。有些人甚至会说 MVC 在服务器端做的事情是错误的。

总而言之:我无法给您直接的 "Yes" 或 "No" 答案。而且我认为没有人可以。任何人都可以为架构框架提供的唯一建议:保持 DRY but avoid over-engineering.