Guiceが生成するクラスについてのコンストラクタをできる限り隠せ
以下のシンプルなインターフェースを考えてみよう。
public interface DataReader { Data readData(DataSource dataSource); }
このインターフェースを以下のようなpublicクラスで実装するのが普通である。
public class DatabaseDataReader implements DataReader { private final ConnectionManager connectionManager; @Inject public DatabaseDataReader( ConnectionManager connectionManager) { this.connectionManager = connectionManager; } @Override public Data readData(DataSource dataSource) { // ... read data from the database return Data.of(readInData, someMetaData); } }
特に問題はないように見える。 Unfortunately, such an inspection excludes the dimension of time and the inevitability of an unguarded code base to become more tightly coupled within itself over time.
深夜をまたぐと何も良いことは起こらない(訳注:?)という古い格言と同様、コンストラクタをpublicにすることは良いことではない。 publicコンストラクタはコードベース内での不法な使用につながる。 これらは必然的に以下をもたらす。
- リファクタリングを難しくする。
- インターフェース/実装間のバリアを破壊する。
- コードベースとのタイトな結合をもたらす。
最も悪いことは、コンストラクタの直接的な使用はGuiceのオブジェクトインスタンス化を回避してしまうことだ。
これを正すには、単純に実装クラスとコンストラクタのビジビリティを変更することである。 通常は、双方をパッケージprivateとすることである。これにより、
- モジュールと同じパッケージのクラスをバインドするようにする。
- unit testing the class through means of direct instantiation
簡単で思い出しやすい例として、publicと@Injectはエルフとドワーフに例えることができる。 彼らは一緒に働くが、しかし理想的な世界では、独立して存在すべきなのである(訳注?)。