2016-11-23 105 views
1

給定兩個類A和B. B包含一個對象A. 在創建B對象時,我們還需要創建其A對象。 所以這個問題:在B的構造函數中實例化A還是在Decalration時刻更好?讓哈瓦看看這個簡單的例子:在另一個實例中創建對象的最佳方法--java

public Class A{ 
//Staff 
} 

- 首先建議

public Class B{ 
//staff 
A a; 
public B(){ 
a = new A() 
} 

}

--Second建議

public Class B{ 
//staff 
A a = new A(); 
public B(){ 
//staff 
} 
} 

那麼,什麼是之間的差異兩種解決方案?

+1

在聲明時實例化是避免空指針異常的常見做法。 但是,在這種情況下,我認爲這並不重要,因爲無論如何你都在實例化它。但前一種方法可以讓你跳過構造函數定義... – Jay

+2

檢查[此anwser](http://stackoverflow.com/questions/4916735/default-constructor-vs-inline-field-initialization) –

+0

取決於事實是否當你創建一個新的'B'時,你需要不同的'A' – XtremeBaumer

回答

1

我建議您使用第一個,因爲您可以將參數添加到構造函數中。

public Class B { 
    A a; 
    public B() { 
     a = new A(); 
    } 
    public B(A a) { 
     this.a = a; 
    } 
} 
+0

當你總是需要相同的初始值時(比如在你的例子中,一個給定大小的數組或特定值的整數),初始值是很好的,但它可以如果你有許多不同的初始化變量(即使用不同的值)的構造函數,那麼初始化程序是無用的,因爲這些更改將被覆蓋並且浪費。 – Jay

1

在你的具體例子中兩者沒有區別。

通常,如果你可以與第二種方法(即初始值設定項)一起使用,則使用它,因爲該對象的創建是在所有構造函數之間共享的。

如果您必須傳遞參數A()來自B()的參數列表,則第一個選項是唯一可用的選項,因爲您無法將參數傳遞給字段初始值設定項。

1

其實沒有什麼區別。編譯器將初始化代碼移動到構造函數體中。這只是關於您的代碼準備情況。

2

我想如果你想通過構造函數或通過適當的setter來設置它,你應該將A的實例傳遞給B的構造函數。否則,你迫使兩個班級緊密聯繫。

+0

這是我的回答更短的版本:-D –

1

對象創建是生命週期管理問題的一部分。這通常是您要分開處理的責任。常見的模式是:

  • 依賴注入
  • 建設者,抽象工廠或工廠方法
  • 單,原型或對象池

對這些念起來看,例如谷歌結果creational patternsdependency injection

我將在這裏關注依賴注入,因爲它是匹配您的示例和結果的最簡單方法,它具有乾淨的可測試代碼。其他最喜歡的模式是建設者或工廠。

依賴注入(或控制反轉)是一種非常常見的模式(雖然通常不稱爲模式,我認爲它是一種)。提供D.I.最好的框架是Spring或Java自己的CDI,但您也可以手動完成,如下所示。

構造器注入

在您的例子一個簡單的使用依賴注入的可能像這樣工作:

public Class Dependency { 
} 

public Class Application { 

    private final Dependency dependency; 

    public Application (Dependency dependency) { 
      this.dependency = dependency; 
    } 
} 

用法:

public static void main(String[] args) { 
    Application application = new Application(new Dependency()); 
} 

注意Application也沒有創造Dependency但預計將提供一個Dependency的實例通過構造函數。這被稱爲構造函數注入。這種方式的優點是你可以使依賴性字段最終。一個缺點是,在許多依賴關係下,構造函數可能會得到太多爭論以保持可理解性。爲了避免這種情況,你可以使用生成器模式,或使用setter注入:

Setter注入

public Class Dependency { 
    public String doStuff(String input) { 
     return input + " stuffed"; 
    } 
} 

public Class Application { 

    private Dependency dependency; 

    public void setDependency(Dependency dependency) { 
      this.dependency = dependency; 
    } 

    public String letsGo(String input) { 
     String stuff = dependency.doStuff(input); 
     return "I called my dependency and it said: " + stuff ; 
    } 
} 

用法:

public static void main(String[] args) { 
    Application application = new Application(); 
    application.setDependency(new Dependency()); 
    System.our.println(application.letsGo("rabbit")); 
} 

輸出:

I called my dependency and it said: rabbit stuffed 

測試

現在關於可測試性。請記住,在單元測試中,我希望能夠在不測試類Dependency的情況下測試類Application。如果Application正在創建它自己的Dependency的實例,這將很難做到。使用依賴注入很容易。下面是使用JUnit和使用的Mockito註解,這是非常標準的例子:

@RunWith(MockitoJUnitRunner.class) 
public class ApplicationTest { 

    @InjectMocks 
    private Application instance; 
    @Mock 
    private Dependency dependency; 

    @Test 
    public void test() { 
     // SETUP 
     String testStuff = "some test stuff"; 
     String input = "Micky";   
     when(dependency.doStuff(input)).thenReturn(testStuff);    

     // CALL 
     String actualResult = instance.letsGo(input); 

     // VERIFY 
     verify(dependency).doStuff(input); 
     String expectedResult = "I called my dependency and it said: " + testStuff; 
     assertEquals(actualResult, expectedResult); 
    } 
} 

這裏是的Mockito創造Application你的一個實例,並注入與@Mock進去註釋任何領域。它會自動決定通過構造函數或setter來實現。該行:

when(dependency.doStuff(input)).thenReturn(testStuff); 

指示模擬Dependency在調用時返回特定值。這意味着我們不會調用真正的Dependency代碼,而是要求Mockito在調用該類時生成該類的假結果。

調用Application實例後,你可以檢查到依賴預期的調用按如下方法制備:

verify(dependency).doStuff(input); 

的Mockito檢查指定的與會者呼籲只有一次,併產生一個錯誤,如果這不是案件。

然後使用assertEquals將實際結果與預期結果進行比較。如果值不相等,則在運行測試時,JUnit會生成一個錯誤。

因此,所有這一切的主要教訓是,對象創建是一個重要的關注點,理想情況下應該使用創建模式或依賴注入來處理對象。通過這樣做,您可以集中精力完成主要任務,使其更易於理解和測試。

備註

直噴本身可能不被視爲一種模式,因爲它不夠具體 - 您可以通過多種方式來構建它。儘管如此,無論何時你看到代碼創建它自己的依賴關係的實例,你都應該考慮到代碼的味道並嘗試重構它。

D.I.的春季實施使用稱爲應用程序上下文的抽象工廠。彈簧支持注射通過簡單地註釋字段與@Autowired(或@Inject):

@Autowired 
private Dependency dependency; 

Dependency實例由彈簧從它通常是與@Configuration註釋一個XML file或類應用上下文而獲得。在應用程序上下文中,您可以指定存在哪些依賴項(bean)以及應該如何設置和連接在一起。

相關問題