問題
ファイルからデータを読み取るためのメソッドDataSource
を提供するクラスReadData
(および他のクラスもありますが、物事をシンプルにしましょう)があるとし.mdb
ます。
var source = new DataSource("myFile.mdb");
var data = source.ReadData();
数年後、データソースとして.xml
ファイルに加えて.mdb
ファイルもサポートできるようにしたいと決めました。「データの読み取り」の実装は.xml
、.mdb
ファイルとファイルでまったく異なります。したがって、システムをゼロから設計する場合、次のように定義します。
abstract class DataSource {
abstract Data ReadData();
static DataSource OpenDataSource(string fileName) {
// return MdbDataSource or XmlDataSource, as appropriate
}
}
class MdbDataSource : DataSource {
override Data ReadData() { /* implementation 1 */ }
}
class XmlDataSource : DataSource {
override Data ReadData() { /* implementation 2 */ }
}
Factoryメソッドパターンの完璧な実装です。残念ながら、DataSource
はライブラリにあり、このようなコードをリファクタリングすると、
var source = new DataSource("myFile.mdb");
ライブラリを使用するさまざまなクライアントで。なんてこった、そもそもファクトリーメソッドを使用しなかったのか?
解決策
これらは私が思いつくことができる解決策です:
DataSourceコンストラクターがサブタイプ(
MdbDataSource
またはXmlDataSource
)を返すようにします。それは私のすべての問題を解決するでしょう。残念ながら、C#はそれをサポートしていません。別の名前を使用:
abstract class DataSourceBase { ... } // corresponds to DataSource in the example above class DataSource : DataSourceBase { // corresponds to MdbDataSource in the example above [Obsolete("New code should use DataSourceBase.OpenDataSource instead")] DataSource(string fileName) { ... } ... } class XmlDataSource : DataSourceBase { ... }
これは、コードの下位互換性を維持する(つまり、
new DataSource("myFile.mdb")
まだ機能するための呼び出し)ために使用することになりました。欠点:名前は、あるべきほど説明的ではありません。作る
DataSource
実際の実装のための「ラッパー」:class DataSource { private DataSourceImpl impl; DataSource(string fileName) { impl = ... ? new MdbDataSourceImpl(fileName) : new XmlDataSourceImpl(fileName); } Data ReadData() { return impl.ReadData(); } abstract private class DataSourceImpl { ... } private class MdbDataSourceImpl : DataSourceImpl { ... } private class XmlDataSourceImpl : DataSourceImpl { ... } }
欠点:すべてのデータソースメソッド(など
ReadData
)を定型コードでルーティングする必要があります。定型コードが好きではありません。冗長であり、コードが乱雑です。
見逃したエレガントなソリューションはありますか?
new
クラスオブジェクトのメソッドではないのは残念です(そのため、クラス自体をサブクラス化(メタクラスとして知られる手法new
)し、実際に行うことを制御できます)が、それはC#(またはJava、C ++)の動作方法ではありません。