2013-10-07 9 views
6

Bir fabrikam var. Bu fabrikanın fabrika dışında üretilebildiği sınıflara izin vermek istemiyorum. Onları soyut, statik yapsam veya onlara özel kurucular verirsem, o zaman onlar anında olamazlar! Bu bir dil kısıtlaması mı, ne?Bir sınıfın bir fabrikanın dışında nasıl örneklenmesini sağlayın

Ben bu kod

var awcrap = new Extrude2013(); // BAD !!! 
awcrap.extrudify(); // I don't want to allow this 

Geri Kalan izin vermek istemiyoruz:

using System; 

namespace testie 
{ 
    public enum ExtrudeType { Extrude2013, Extrude2014 } 

    public interface IExtrudeStuff { 
     void extrudify(); 
    } 

    public class Extrude2013 : IExtrudeStuff { 
     public void extrudify(){ 
      Console.WriteLine ("extrudify 2013"); 
     } 
    } 

    public class Extrude2014 : IExtrudeStuff { 
     public void extrudify(){ 
      Console.WriteLine ("extrudify 2014"); 
     } 
    } 
    public static class ExtrudeFactory { 
     public static IExtrudeStuff Create(ExtrudeType t) { 
      switch (t) { 
       case ExtrudeType.Extrude2013: return new Extrude2013(); 
       case ExtrudeType.Extrude2014: return new Extrude2014(); 
       default: return null; 
      } 
     } 
    } 

    class MainClass { 
     public static void Main (string[] args) { 
      // Now for the pretty API part 
      var o = ExtrudeFactory.Create (ExtrudeType.Extrude2013); 
      o.extrudify(); 
      var p = ExtrudeFactory.Create (ExtrudeType.Extrude2014); 
      p.extrudify(); 

      var awcrap = new Extrude2013(); // BAD !!! 
      awcrap.extrudify(); // I don't want to allow this 
     } 
    } 
} 
+0

Bu mümkün değil. 'new' anahtar sözcüğü, örneğe izin verecektir. –

+0

Neden fabrika sınıfında özel yuvalanmış sınıflar yapmıyoruz? –

+0

Dahili mi arıyorsunuz? –

cevap

5

Tamamen bu izin vermemek mümkün değil. bir dil "kısıtlama" olsun ya da olmasın görüş meselesi olabilir, ama size düşünebiliriz şeyler vardır olacaktır:

  • yapıcı internal olun. Bu, bildirme tertibatının içindeki herhangi bir türün yapıcıyı çağırmasına izin verecektir, fakat montajın dışında hiçbir şey yoktur. Bu, söz konusu montajda yazdığınız herhangi bir kodun fabrikayı çağırmaktan sorumlu olduğu anlamına gelir ve aynı zamanda kurucuyu arayamayacağı için başka bir derlemede sınıfın alt türlerini bildiremeyeceğiniz anlamına da gelir.
  • Benzer bir yaklaşımı (o fabrikanın dışında başvurulan asla olacağından, fabrikanın bir alt sınıf olarak, hatta private) Eğer soyut (veya bir arabirim) maruz sınıf, daha sonra bir internal ilan yapmak olacaktır yazın soyut sınıfı veya arayüzü uygular.
  • Yalnızca fabrikanın yapıcıda sağlayabildiği belirteci belirtin. Bu, DataTable sınıfının nasıl çalıştığıdır. Yapıcı hala denilen olabilir iken, kullanıcı değeri için null geçmek zorunda kalacak ve en az onlar bunu yaparken gerektiğini açıkça görecektir.
+0

Bir RequireToken güvenli nasıl yazılır? Ya da derleyici tarafından zorlanıyor? RequiredToken türü nedir? –

+0

@dave: Kullanıcının hala "null" kelimesini geçebileceği anlamında * gerekli * olamaz. Fakat çalışma zamanında başarısız olur ve kodu yazmaması gereken kişiyi yazan kişi için oldukça açık olmalıdır. –

+0

@dave: Ayrıca, kullandığınız sınıfların hepsinin aynı montajda olması durumunda, ilk iki yaklaşımın tercih edilebileceğini unutmayın. Son yaklaşım, yalnızca tanımlayıcı montajın dışında tanımlanmış alt sınıflara izin vermeniz gerekiyorsa gereklidir. –

2

Factory Pattern bütün mesele yalnızca Fabrika seçip bir nesneyi nasıl bilir ve bu sadece bir arabirim değil somut sınıf içinden örneklenmiş nesnenin işlevselliği sunar. Nesnenin kurucusunun özel olması, Factory'un kendisini başlatılamamasından dolayı başarısız olur.

Çözüm:

1- Extrude20XX sınıfların her türlü böyle IExtrudeStuff olarak uygulamak bir interface sınıfını tanımlar.

2-

özel bir iç içe sınıfları olarak Factory sınıfı içinde Extrude20XX sınıfları sarın.

3-

her ExtrudeXX sınıflarında arayüzü IExtrude uygulamak.

4- Yaz bir (statik) Create (t) yöntemi gibi:

public static class ExtrudeFactory { 
public static IExtrudeStuff Create(ExtrudeType t) { 
{ 
    switch (t) { 
     case ExtrudeType.Extrude2013: return new Extrude2013(); 
     case ExtrudeType.Extrude2014: return new Extrude2014(); 
     default: return null; 
    } 
} 
} 
+0

Bu çözüm, iç içe alt sınıflar gibi görünüyor. Ne güzel olurdu Extrude2013 gibi sınıflar için ayrı dosyaları olması (bu örneklenemeyen), daha sonra bu sınıflar için fabrika içinde özellikleri var olabilir * 0 * –

+0

@dave uygulanabilir İyi bir uygulama olmasına rağmen, sınıfları dağıtmak Ayrı dosyalar arasında aynı montajda olmadıkça hiçbir şey değişmez. Açılış, “Fabrika” sınıfının içinde özel olması gerektiğidir. Bu şekilde "Fabrika" sınıfı kısmi olabilir ve somut sınıflar boyunca genişler. – Alireza

+0

Evet, tamamen kodun operasyonel anlamını değiştirmeyecek, ancak fark okunabilirlik –