Dmi*_*ich 1 java rest model-view-controller design-patterns spring-mvc
我们有一个 Spring MVC 应用程序,大多数 REST 操作是每个资源唯一的 GET 操作。因此,目前我们有许多控制器,其唯一的 GET 方法彼此没有区别(即使在 url、内容类型、参数等方面)。
为了消除这种重复,我们的团队成员提供了一个控制器,其中只有一个 GET 操作和一个带有服务的映射(资源名称 -> 资源服务)。
但是我们看到了诸如Spring注入调优更复杂,没有机会添加对内容类型,参数的一些限制 - 一言以蔽之的自定义操作等缺点。此外,还有多个资源驻留在单独的控制器中。此外,我不希望至少有一种简单的方法可以以多种方式记录 Swagger 中的唯一方法(有不同的描述)。
所以对我来说,一方面是代码较少,但另一方面是操作定制、架构混合、缺乏适当的文档或至少复杂的配置的机会有限。我认为在这里制定一种方法不是一个好方法。
我对吗?如果是我怎么证明。如果不是为什么?感谢您的时间和想法!
小智 6
你是对的。简而言之,根据单一职责原则,每个控制器应该只做一项工作(只处理一个 URL)。
您完美地描述了通用控制器将处理的问题。还要考虑一下,如果某个控制器现在完全符合通用规则,但下个月需要特定的东西怎么办?您必须复制粘贴代码,然后添加新代码。所以一段时间后,你会被庞大而复杂的通用控制器和重复的代码弄得一团糟。没有人可以预测它的速度有多快,因为开发团队可能会意外地添加业务需求。
另一方面,您的队友减少重复代码的愿望是正确的。至少不是所有的开发人员都想把时间花在让代码更干净上。而大多数人需要获得认可(确保他们的意见有价值)。所以不要把他送走:)
我可以推荐什么:引入抽象父级并为类似的控制器使用继承和模板模式
/** 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}
}
Run Code Online (Sandbox Code Playgroud)
事实上,我在一个项目中假设了类似的解决方案。使用诸如“引入方法”和“移至父级”之类的 IDE 功能,我在一天内重构了数十个类。
希望你或你的队友能在几天内实现和比较这样的想法
| 归档时间: |
|
| 查看次数: |
1035 次 |
| 最近记录: |