为多个资源设置一个控制器的优缺点

时间:2017-08-16 13:09:30

标签: java rest spring-mvc design-patterns model-view-controller

我们有一个Spring MVC应用程序,大多数REST操作是每个资源唯一的GET操作。因此,目前我们有许多控制器,只有GET方法彼此不同(即使在网址,内容类型,参数等方面)。

为了消除这种重复,我们的团队成员提供了使用唯一的GET操作和带服务的地图(资源名称 - >资源服务)制作一个控制器。

但是我们看到了更复杂的Spring注入调整这样的缺点,没有机会对内容类型,参数添加一些限制 - 用一个单词定制操作。此外,有几个资源驻留在单独的控制器中。另外,我不希望至少有简单的方法以多种方式记录Swagger中唯一的方法(有不同的描述)。

因此,对我来说,一方面代码较少,但另一方面是操作定制,架构组合,缺乏适当文档或至少复杂配置的受限机会。我不认为这是制定一种方法的好方法。

我是对的吗?如果是这样我怎么能证明它。如果不是为什么?谢谢你的时间和想法!

2 个答案:

答案 0 :(得分:2)

是的,你是对的。简而言之,根据single responsibility principle,每个控制器应该只执行一个作业(仅处理一个URL)。

您完美地描述了通用控制器将要处理的问题。还要考虑一下如果某个控制器现在完全符合通用规则但下个月需要特定的东西呢?您必须复制粘贴代码然后添加新代码。因此,经过一段时间后,您会遇到庞大而复杂的通用控制器重复代码。没有人能够预测它有多快,因为可以为开发团队意外添加业务需求。

另一方面,你的队友正确地希望减少重复的代码。至少并非所有开发人员都希望花时间使代码更加干净。大多数人需要获得认可(确保他们的意见具有价值)。所以不要把他送走:)。

我可以推荐:引入抽象父级并使用继承和类似控制器的Template模式

/** Interface mainly works as a marker. 
  At first look, interface isn't necessary but it'll improve maintainability.
  Next year you say 'thank you' to yourself  */
interface IController { 
  //some methods which will implement EACH controller even the most specific
  public void doGet(params)
}
abstract class AbstractController implements IController {
 /** Class implements default behavior for controllers.
     Implementation written so child classes could adopt behaviour easily*/
  @Override
  public void doGet(params) {
    // use Template pattern
    doLog(params);
    prepareStuff();
    process();
  }
  // common stuff which should be done at first
  protected void doLog(params) { // your favorite logger here}
  // extension point for inherited classes
  abstract protected void prepareStuff();
  // here is the real processing for default controller
  public void process() {
    //implement common processing for GET request
  }
  // Prefer to use protected method instead of field
  protected String getURL() { return DEFAULT_URL;}
}
// usual controller has nothing special
class Controller1 extends AbstractController {
  @Override
  protected String getURL() { return "url1";}
  @Override
  protected prepareStuff() {// do nothing}
}
// do some specific preparation/checks
class Controller2 extends AbstractController {
  @Override
  protected prepareStuff() {//preparation/checks here }
  /** Note I 'forget' to override getURL() so it'll process DEFAULT_URL.
   It could be useful if AbstractController calculates url dynamically and
   you don't want to write boilerplate strings "/myApp/section7".
   Also you could write abstract getURL()
  */
}
/** custom controller but you want to re-use some common code. 
In fact I would not recommend this way as usual approach */
class Controller3 extends AbstractController {
  /** Overriding this method totally discards the Template pattern. 
      It could (and will) lead to confusing and errors*/
  @Override
  public void doGet(params) { // new implementation }
  @Override
  protected prepareStuff() {
    // you don't need it but you have to override since it abstract
  }
}
// totally custom controller. Implements interface just as a marker
class SpecificController implements Controller {
  // In order to support legacy code just call method wich has been already written. You even no need to rename it.
  @Override
  public void doGet(params) { specificMethod();}
  // lagacy method which probably is used somewhere else
  public void specificMethod() {  // the actual logic here}
}

事实上,我认为项目中有类似的解决方案。使用IDE函数,如'引入方法'和'移动到父级',我在一天内重构了几十个类。

希望您或您的队友能够在几天内实施并比较这样的想法

答案 1 :(得分:0)

让所有帖子都拥有一个控制者是个好主意吗?

AGATC 0
AATG 43
TATC 5

{ 使用HelperTrait;

class PostController extends BaseController