有多个资源有一个控制器的优点和缺点

问题描述:

我们有一个Spring MVC应用程序,大多数REST操作是每个资源唯一的GET操作。所以目前我们有很多控制器,只有GET方法,彼此没有区别(甚至在URL,内容类型,参数等等)。有多个资源有一个控制器的优点和缺点

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

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

因此,对我来说,一方面是较少的代码,另一方面是受限制的操作定制机会,混合体系结构,缺乏适当的文档或至少复杂的配置。我认为在这里做一个方法并不是一个好方法。

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

是的,你是对的。简而言之,根据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功能,如“引入方法”和“移到父级”,我在一天内重构了几十个类。

希望你或你的队友可以实现在几天

+0

谢谢你的比较这样的想法,我真的很感谢你抽出时间做答案!但是我没有看到vanilla servlet之间的体系结构差异,那么:C这种情况似乎与使用命令模式相似 –

+0

1.通过将重复代码引入父级AbstractController和2.您有扩展点来更改behaivor(差异你的队友建议:单个控制器难以扩展) – ADS

+0

作为替代方案有多个GET方法的控制器? –