Sorun
Diyelim ki bir dosyadan veri okumak için DataSourcebir ReadDatayö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 .xmlek olarak .mdbdosyaları destekleyebileceğime karar veriyorum . "Veri okuma" uygulaması .xmlve .mdbdosyalar 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, DataSourcebir 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 (
MdbDataSourceveyaXmlDataSource) 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.DataSourceGerç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?
newSı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 newgerçekte ne yaptığını kontrol edebilirsiniz ) ama C # (veya Java veya C ++) böyle çalışmaz.