有多个资源有一个控制器的优点和缺点
我们有一个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功能,如“引入方法”和“移到父级”,我在一天内重构了几十个类。
希望你或你的队友可以实现在几天
谢谢你的比较这样的想法,我真的很感谢你抽出时间做答案!但是我没有看到vanilla servlet之间的体系结构差异,那么:C这种情况似乎与使用命令模式相似 –
1.通过将重复代码引入父级AbstractController和2.您有扩展点来更改behaivor(差异你的队友建议:单个控制器难以扩展) – ADS
作为替代方案有多个GET方法的控制器? –