Sorun
Diyelim ki bir dosyadan veri okumak için DataSource
bir ReadData
yöntem sağlayan (ve belki de diğerlerini basitleştirelim) adlı bir sınıfım var .mdb
:
var source = new DataSource("myFile.mdb");
var data = source.ReadData();
Birkaç yıl sonra, veri kaynağı olarak dosyalara .xml
ek olarak .mdb
dosyaları destekleyebileceğime karar veriyorum . "Veri okuma" uygulaması .xml
ve .mdb
dosyalar için oldukça farklıdır ; bu nedenle, sistemi sıfırdan tasarlayacak olsaydım, şöyle tanımlardım:
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 */ }
}
Harika, Fabrika yöntemi modelinin mükemmel bir uygulaması. Ne yazık ki, DataSource
bir kütüphanede yer alıyor ve kodun yeniden düzenlenmesi, mevcut tüm çağrıları kıracak
var source = new DataSource("myFile.mdb");
kütüphaneyi kullanan çeşitli istemcilerde. Vay be, neden ilk etapta fabrika metodunu kullanmadım?
Çözümler
Bunlar ortaya çıkarabileceğim çözümler:
DataSource yapıcısının bir alt tür (
MdbDataSource
veyaXmlDataSource
) döndürmesini sağlayın . Bu bütün sorunlarımı çözer. Ne yazık ki, C # bunu desteklemiyor.Farklı adlar kullanın:
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 { ... }
Ben kod geriye dönük uyumlu (yani
new DataSource("myFile.mdb")
hala çalışmaya çağırır ) tutar çünkü ben bunu kullanarak sona erdi . Dezavantajı: İsimler olması gerektiği kadar açıklayıcı değildir.DataSource
Gerçek uygulama için bir "sarıcı" yapın :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 { ... } }
Dezavantaj: Her veri kaynağı yöntemi (örneğin
ReadData
), kaynak plakası koduyla yönlendirilmelidir. Ortak koddan hoşlanmıyorum. Gereksizdir ve kodu keser.
Herhangi var mı zarif kaçırdım o çözüm?
new
Sınıf nesnesinin bir yöntemi olmayan bir utanç (böylece sınıfın kendisini - metasınıflar olarak bilinen bir teknik - alt sınıfı sınıflandırabilir ve new
gerçekte ne yaptığını kontrol edebilirsiniz ) ama C # (veya Java veya C ++) böyle çalışmaz.