オブジェクトの作成は、ライフサイクル管理の問題の一部です。これは通常、別個に扱いたい責任です。一般的なパターンは以下のとおりです。
- 依存性注入
- ビルダー、抽象工場や工場方法
- シングルトン、プロトタイプやオブジェクトプール
これらの上に読むには、たとえば、Googleがcreational patternsのために結果を確認し、 dependency injection。
それはきれいで、テスト可能なコードにあなたの例と結果を照合最も簡単な方法ですので、私は依存性の注入にここに焦点を当てます。他のお気に入りのパターンはビルダーまたは工場です。
依存性の注入(または制御の反転)は、(通常のパターンと呼ばれていないが、私はそれが1だと思う)非常に一般的なパターンです。 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
のインスタンスがそれに供給されることを期待するコンストラクタを介してこれはコンストラクタインジェクションと呼ばれます。この方法の利点は、依存関係フィールドを最終的にすることができることです。欠点は、多くの依存関係では、コンストラクターが理解できないほど多くの引数を取得する可能性があることです。
セッター・インジェクション
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
テストあなたはBuilderパターンを使用するか、セッター・インジェクションを使用することができることを避けるために、
今、テスト容易性について。単位テストでは、クラスをテストせずにクラス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
で注釈を付け任意のフィールドを噴射します。コンストラクタまたはセッターを介して自動的に決定します。
when(dependency.doStuff(input)).thenReturn(testStuff);
モックDependency
は、呼び出されたときに特定の値を返すように指示します。これは、実際のDependency
コードを呼び出すのではなく、呼び出されたときにそのクラスから偽の結果を生成するようにMockitoに依頼することを意味します。指定されたコールが正確に一度行われ、これがない場合は、エラーが発生した場合
verify(dependency).doStuff(input);
Mockitoチェック:次のように依存関係に予想される呼び出しが行われたかどうかをチェックすることができApplication
インスタンスを呼び出した後
場合。
assertEquals
を使用すると、実際の結果が予想される結果と比較されます。値が等しくなければ、テストを実行するとJUnitによってエラーが生成されます。
この主な教訓は、オブジェクトの作成は、理想的には、創造的パターンまたは依存性注入のいずれかを使って別々に扱われるべきであるということです。これを行うことで、主なタスクを実行することにクラスを集中させ、理解しやすくテストすることができます。
備考
D.I.それは十分ではないため、おそらくパターンとは見なされません。いくつかの点でそれを設計することができます。それでも、独自の依存関係のインスタンスを作成するコードを見るときはいつでも、コードのにおいを考慮して、それをリファクタリングする必要があります。
D.I.アプリケーションコンテキストと呼ばれる抽象ファクトリを使用します。スプリングは、単に@Autowired
(又は@Inject
)のフィールドに注釈を付けることにより、注入をサポート:
@Autowired
private Dependency dependency;
Dependency
インスタンスが通常@Configuration
で注釈XML fileまたはクラスであるアプリケーションのコンテキストからバネにより得られます。アプリケーションコンテキストでは、どの依存関係(Beans)が存在するか、それらをどのように設定して配線するかを指定できます。
nullポインタ例外を回避するために、宣言時にインスタンス化するのが一般的です。 しかし、この場合は、とにかくインスタンス化しているので、実際には問題ではないと思います。しかし、前のアプローチでは、コンストラクタの定義をスキップできます。 – Jay
チェック[this anwser](http://stackoverflow.com/questions/4916735/default-constructor-vs-inline-field-initialization) –
は、新しい 'B'を作成するときに異なる' A'が必要です – XtremeBaumer