以下のコンストラクターがあります。コンストラクターでワークブックを作成します。私は、理想的には、コンストラクターでオブジェクトを作成するべきではなく、渡された割り当てだけが必要であると読みました。
public ExcelWriter() {
workbook = new HSSFWorkbook();
//other code
}
上記のような固定オブジェクトを作成しても大丈夫ですか?理想的な代替ソリューションとは何ですか?ユニットテストの観点から?他のクラスのメソッドコードの呼び出しからワークブックを渡す場合、そこにもワークブックオブジェクトを作成する必要があります。
後でより良いアプローチですか?コンストラクターアプローチと比較して、どのように優れているか重要ですか?
初心者のプログラマにとってはこれで問題ありません。
ただし、前述のように、このExcelWriter
クラスをユニットテストする場合は、HSSFWorkbook
オブジェクトを自分で作成するのではなく、コンストラクターの引数として指定できます。このようにして、実際のコードをコードで使用し、モックをユニットテストで使用できます。この方法は 依存性注入 と呼ばれます。
したがって、コンストラクタは次のようになります。
public ExcelWriter(HSSFWorkbook hssfWorkBook) {
workbook = hssfWorkBook;
// other code
}
次に、コードの他の場所で、そのコンストラクターを呼び出します。
HSSFWorkbook myWorkbook = new HSSFWorkbook();
ExcelWriter myExcelWriter = new ExcelWriter(myWorkbook);
そしてあなたのユニットテストは次のようなものになります:
HSSFWorkbook myMockedWorkbook = // create a mock
ExcelWriter testWriter = new ExcelWriter(myMockedWorkbook);
これをさらによくしたい場合は、インターフェースを使用して、2つの別々のクラスを作成します。
public interface IWorkbook {}
public class RealWorkbook implements IWorkbook {
// this is the one for in your code
}
public class FakeWorkbook implements IWorkbook {
// this is the one you use in your unit test
}
現実の世界で理想的なものはありません。しかし、代替ソリューションは 依存性注入 と呼ばれます:
public class ExcelWriter {
Workbook workbook;
public ExcelWriter(Workbook workbook) {
this.workbook = workbook;
}
//other code
}
public void main(){
Writer writer = new ExcelWriter( new HSSFWorkbook() );
//other code
}
このようにして、ExcelWriter
はあらゆる種類のWorkbook
で機能します。
それは意味論に分解されます。
インスタンス化がラッパーのコンテキスト内にあり、機能をWorkbook(継承または構成)に拡張する場合は、コンストラクター内でオブジェクトをインスタンス化することで問題ありません。ルール「継承より構成」を適用します。
オブジェクトを構成して分離した新しいセマンティクスを作成する場合は、具体化クラスをインスタンス化するためにそれを知っている必要があるため、具象クラスに依存するかどうかを自問する必要があります。
具体的な依存関係(依存関係の逆転の原則に違反する可能性がある)に問題がない場合、コンストラクターでのオブジェクトのインスタンス化または遅延初期化は、意味的に同じです。遅延初期化は、必要になるまでインスタンス化を延期するだけです。オブジェクトが作成された時点から抽象化します。
抽象化されたワークブックの複数のバージョンがある場合は、この抽象化されたオブジェクトをコンストラクタで渡すことをお勧めします。高レベルのオブジェクトでは、コンテナーの機能を検討する必要があります。依存性注入技術にはいくつかの可能性があります。