2017-08-16 71 views
0

我們有一個Spring MVC應用程序,大多數REST操作是每個資源唯一的GET操作。所以目前我們有很多控制器,只有GET方法,彼此沒有區別(甚至在URL,內容類型,參數等等)。有多個資源有一個控制器的優點和缺點

爲了消除這種重複,我們的團隊成員提供了一個只有GET操作的控制器和一個帶有服務(資源名稱 - >資源服務)的映射。

但是我們認爲這樣的缺點更復雜Spring注入優化,沒有機會在內容類型,參數上添加一些限制 - 用一個詞自定義操作。此外,還有幾個資源駐留在單獨的控制器中。另外我不希望至少有簡單的方法來以多種方式記錄Swagger中唯一的方法(具有不同的描述)。

因此,對我來說,一方面是較少的代碼,另一方面是受限制的操作定製機會,混合體繫結構,缺乏適當的文檔或至少複雜的配置。我認爲在這裏做一個方法並不是一個好方法。

對嗎?如果是這樣,我怎麼能證明它。如果不是爲什麼?感謝您的時間和想法!

回答

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功能,如「引入方法」和「移到父級」,我在一天內重構了幾十個類。

希望你或你的隊友可以實現在幾天

+0

謝謝你的比較這樣的想法,我真的很感謝你抽出時間做答案!但是我沒有看到vanilla servlet之間的體系結構差異,那麼:C這種情況似乎與使用命令模式相似 –

+0

1.通過將重複代碼引入父級AbstractController和2.您有擴展點來更改behaivor(差異你的隊友建議:單個控制器難以擴展) – ADS

+0

作爲替代方案有多個GET方法的控制器? –