2012-02-03 55 views
8

假設你使用生成器模式創建一個類名的人,假設生成器類包含的方法body()head()arms()當然build()的,你考慮方法head()build()強制性的這一類的用戶。如何標記一個強制性的方法?

我們想以某種方式標記這些方法是必須的,如果可能的話使用註釋。如果這個類的用戶試圖構建一個Person實例但忘記調用其中任何一個方法,我們希望得到某種警告 - 無論是來自java編譯器,還是來自Eclipse或Maven,我們用它來構建我們的項目 - 他們中的任何人都會這樣做。

可以嗎?你會建議哪種方式?

+0

懷疑你可以在編譯時做到這一點,除非*非常*特殊情況。在運行時應該很容易地進行這樣的檢查(儘管我一直這樣做)。 – NPE 2012-02-03 09:22:48

+1

我無法想象一種方法來做到這一點,然後將強制屬性作爲參數添加到構建器構造函數中,或者在調用'build'時拋出異常,但我很好奇如果有人有更好的主意。 – 2012-02-03 09:24:11

回答

15

下面是使用不同類型做出一些地方強制爲例(它也會讓你叫強制方法的順序排列):

package test; 

import test.StepOne.StepThree; 
import test.StepOne.StepTwo; 
import test.StepOne.LastStep; 

public class TestBuilder { 

    public static void main(String[] args) { 

     String person1 = PersonBuilder.newInstance().head("head").body("body").arm("arm").leg("leg").build(); 

     String person2 = PersonBuilder.newInstance().head("head").body("body").arm("arm").build(); 

    } 

} 

interface StepOne { 

    // mandatory 
    StepTwo head(String head); 

    interface StepTwo { 
     // mandatory 
     StepThree body(String body); 
    } 

    interface StepThree { 
     // mandatory 
     LastStep arm(String arm); 
    } 

    // all methods in this interface are not mandatory 
    interface LastStep { 
     LastStep leg(String leg); 
     String build(); 
    } 

} 

class PersonBuilder implements StepOne, StepTwo, StepThree, LastStep { 

    String head; 
    String body; 
    String arm; 
    String leg; 

    static StepOne newInstance() { 
     return new PersonBuilder(); 
    } 

    private PersonBuilder() { 
    } 



    public StepTwo head(String head) { 
     this.head = head; 
     return this; 
    } 

    public LastStep arm(String arm) { 
     this.arm = arm; 
     return this; 
    } 

    public StepThree body(String body) { 
     this.body = body; 
     return this; 
    } 

    public LastStep leg(String leg) { 
     this.leg = leg; 
     return this; 
    } 

    public String build() { 
     return head + body + arm + leg; 
    } 
} 


編輯

的OP是如此這個答案給他留下了深刻的印象,他完全在 blog中寫下了這個答案。這是一個聰明的建設者模式,完整的治療值得引用這裏。

+0

這是一個非常酷的方法!但是可以在不強迫訂單的情況下完成。即像Mandatory和NonMandatory這樣的接口? – uzilan 2012-02-03 11:29:53

+0

不,您必須強制執行命令,因爲在每個界面中您都需要一個返回下一步的方法,因此只要您將一些方法放入其中一個界面中,您就會強制只調用其中一個方法以便能夠導航到下一步...... – pgras 2012-02-03 11:49:53

+0

但是你可以添加不添加屬性的接口方法(例如'PersonBuilder.newInstance()。head(「head」)。doesntHaveABody()。arm(「arm」)' – yannick1976 2015-10-22 10:45:35

1

編譯器沒有辦法。

你能做的就是扔從build()方法該建築工地未正確初始化運行時異常(並且具有在Maven的測試階段調用的測試)

但你也可以有build(..)接受HeadDetails目的。這種方式tou不能在沒有指定強制參數的情況下調用構建。

0

也許在build()之內,你可以檢查是否所有必需的方法都被調用過。可疑的Person實例有一些內部的完整性檢查,由build()觸發。

當然這種檢查運行時行爲並沒有什麼靜態分析你描述它。

0

是不可能在Person的構造函數中調用這些方法?

+1

構建器模式的構想之一是用戶可以選擇她想要調用的構建器中的哪些方法。另一種方法是避免具有許多參數和許多重載的構造函數(其中涵蓋了創建此對象的所有可能方式)。我擔心你的建議可能會打破這些好處。我們希望保留用戶使用任何他們需要的方法創建Person對象的自由,但同時聲明一些強制方法被調用,最好是在構建時。 – uzilan 2012-02-03 10:00:00

1

爲什麼不叫身體(),頭(),武器()在build() - 如果它真的是強制性的,回國的人在build()方法的方法?

[編輯]

短的例子:

public class Builder { 

private final String bodyProp; 

private final String headProp; 

private final String armsProp; 

private String hearProps; 

public Builder(String bodyProp, String headProp, String armsProp) { 
    super(); 
    this.bodyProp = bodyProp; // check preconditions here (eg not null) 
    this.headProp = headProp; 
    this.armsProp = armsProp; 
} 

public void addOptionalHair(String hearProps) { 
    this.hearProps = hearProps; 
} 

public Person build() { 
    Person person = new Person(); 

    person.setBody(buildBody()); 
    // ... 

    return person; 
} 



private Body buildBody() { 
    // do something with bodyProp 
    return new Body(); 
} 


public static class Person { 

    public void setBody(Body buildBody) { 
     // ... 
    } 
} 

public static class Body { 
} 
} 
+0

btw。如果body,head和arms需要一些參數,並且它們也是強制的,那麼將它們放入構建器的構造函數中。 – ollins 2012-02-03 09:58:23

+0

這些方法需要參數,我必須發送到build()方法。這是對我所瞭解的建築模式。 – uzilan 2012-02-03 10:17:37

3

我認爲正確的使用生成器模式會解決您遇到的問題。

我會創建類PersonBuilder,其中將包含方法setBody()setArms()和每隔一個可選參數設置方法。構建器的構造函數將採用所需的參數。然後方法build()將返回Person的新實例。

public class PersonBuilder 
{ 
    private final Head head; 
    private Body body; 
    private Arms arms; 

    public PersonBuilder(Head head) 
    { 
     this.head = head; 
    } 

    public void setBody(Body body) 
    { 
     this.body = body; 
    } 

    public void setArms(Arms arms) 
    { 
     this.arms = arms; 
    } 

    public Person build() 
    { 
     return new Person(head, body, arms); 
    } 
} 

或者你可以在Head參數傳遞給方法build(),但我更喜歡通過它在構造函數來代替。

相關問題