是否需要通过创建 "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.
我目前正在做一个个人项目,我已经实现了服务层。我更喜欢独立存储服务,这样我就不会在一个文件中拥有一个大型库。以下文件结构的简要示例
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.