C # “Static” kullanmayın mu?


109

Kod incelemesi için diğer bazı mimarlara yazdığım bir başvuruyu gönderdim. Onlardan biri neredeyse hemen bana geri döndü ve "statik kullanma" dedi. Statik sınıf ve yöntemlerle otomatikleştirilmiş testler yazamazsınız. "Statik" önlenmeli. "

Kontrol ettim ve derslerin 1 / 4'ü "statik" olarak işaretlendi. Sınıfın bir örneğini oluşturamayacağım zaman statik kullanırım çünkü sınıf kod boyunca kullanılan tek bir genel sınıftır.

Statik kodla kullanılamayan alaycı, IOC / DI teknikleriyle ilgili bir şeyden bahsetmeye devam etti. 3. parti kütüphanelerinin test edilemezliklerinden dolayı statik olmalarının şanssız olduğunu söylüyor.

Bu diğer mimar doğru mu?

güncelleme: işte bir örnek:

APIManager - bu sınıf bir sonraki izin verilen süre ile birlikte çağırdığım 3. taraf API'lerinin sözlüklerini tutar. Birçok 3. tarafın hizmet şartlarında sahip olduğu API kullanım sınırlarını zorlar. Her yerde kullanıyorum Thread.Sleep (APIManager.GetWait ("ProviderXYZ")) adlı bir üçüncü taraf servisini arıyorum. arama yapmadan önce. Burada her şey iş parçacığı güvenli ve C # TPL ile harika çalışıyor.


37
staticiyi; static tarlaların çok dikkatli bir şekilde ele alınması gerekiyor
Marc Gravell

2
3. parti kütüphaneleri için neden test yazdı? Genelde, 3. parti kütüphanesinin yaratıcılarının testlerini yaptıklarını varsayarak kendi kodunuzu test etmiyor musunuz?
Hayır,

3
Bu itiraz benim için biraz fazla genel. Çoğu durumda, statik sınıfı mocj yapmazsınız, tartışmalarla alay edersiniz. Alay gerektiren bir toplam sınıf olduğu statik alan, ardından evet.

8
Açıkçası meslektaşlarınızın ciddi bir durumu var - akut sistemik bir OOPus eritematozus. En kısa zamanda bir tedaviye ihtiyaçları var!
SK-mantığı

6
Cevaplar sağlayan bir cevap bölümü var, neden birisinin bir cevap / öneri verme girişiminde insanların yorum yaptığını anlamıyorum.
peteski 11:12

Yanıtlar:


121

Statik sınıfların durumu koruyup korumamasına bağlı Şahsen, statik sınıfta bir araya getirilen durumsuzluk işlevleriyle ilgili bir sorunum yok.


111
Doğru. Yan etkisi olmayan statik fonksiyonlar, hepsinin en test edilebilir fonksiyonlarıdır.
Robert Harvey,

9
Buna +1, ancak bir güvenlik maddesi ile: Hemen hemen her soyut algoritma vatansız, ancak bu, vatansız statik sınıf ya da yöntem olarak uygulamanız gerektiği anlamına gelmiyor. Bu şekilde uygulamak, onu kullanan tüm kodların kendisine zor bir şekilde bağlanmasına neden olur. Bu, örneğin sıralama algoritmasını statik bir yöntem olarak uygularsanız ve bunu proje boyunca kullanırsanız , sıralamayı geçici olarak başka bir algoritma ile değiştiremezsiniz , yani test amaçlı ve sorunlu alanı daraltmak için. Bu birçok durumda büyük bir engeldir. Bunun yanı sıra, makul şekilde kullanılırsa statik tamamen tamamdır.

11
Kısacası: en test edilebilir fonksiyonlar, fakat diğer kodu daha test edilebilir hale getirmedikleri sürece ! Mimarın muhtemelen kastettiği buydu.

4
@ tereško: C # dili, yöntemi çağırmak için sınıfın bir örneğini oluşturmak istemiyorsanız, statik bir sınıfın parçası olmak için statik yöntemler gerektirir. Belki de "sınıf" demek ve "sınıf" demek değildir.
Robert Harvey,

8
@quetzalcoatl: Bir temsilciyi (yani farklı bir algoritmayı) statik bir yönteme geçirmek tamamen yasaldır; Linq'deki uzatma yöntemlerinin tümü statik yöntemlerdir. Örnek: msdn.microsoft.com/en-us/library/…
Robert Harvey

93

Bu konuda çok genel. O haklı, test etmeyi engelliyor. Ancak, staticsınıflar ve yöntemlerin kendi yerleri vardır ve bu gerçekten bağlama bağlıdır. Kod örnekleri olmadan gerçekten söyleyemezsin.

Sınıfın bir örneğini oluşturamayacağım zaman statik kullanırım çünkü sınıf kod boyunca kullanılan tek bir genel sınıftır.

Bu şiddetli kod kokusu olabilir. Sınıfları ne için kullanıyorsun? Veri tutmak için? Bir veritabanına erişmek için? O zaman haklı. Bu durumda bağımlılık enjeksiyonuna bakmalısınız, çünkü böyle bir statik sınıf etkili bir singletondur.

Bunları uzatma yöntemleri veya durumu değiştirmeyen ve sadece sağladığınız parametreler üzerinde çalışan yardımcılar için kullanıyorsanız, bunlar genellikle iyidir.


3
İfadenin genel olduğu ve test edilebilecek uzatma yöntemlerinden bahsettiği ve bağımlılıkları hala bildiğim kadarıyla alay edilebildiği için +1.
Hayır,

4
Tek bir sınıf örneği olarak örtülü bir singleton gibi statik, bu karışıklığa yol açacak ....

"Bir veritabanına erişmek için?" neden olmasın ? Eğer masa adaptörü statik değilse, o zaman kesinlikle yazılan statik bir sınıf @ yazılan veri kümesi, yanlış bir şey yok .... eğer referans ya da örnek ile noktanızı kanıtlamadıkça
Matematik

27

Kontrol ettim ve derslerin 1 / 4'ü "statik" olarak işaretlendi. Sınıfın bir örneğini oluşturamayacağım zaman statik kullanırım çünkü sınıf kod boyunca kullanılan tek bir genel sınıftır.

Yapılacak en iyi şey, kodunuzu denemek ve birim sınamaktır. Tekrarlanabilir, bağımsız, basit ve aynı anda yalnızca bir yöntem test eden testler tasarlamayı deneyin. Testlerinizi farklı rasgele sırayla çalıştırmayı deneyin. Kararlı "yeşil" yapı alabilirsiniz?

Eğer evet ise, kodunuzu savunmak için geçerli bir nokta. Bununla birlikte, zorluklarınız varsa, o zaman belki örnekleme yöntemlerine başvurmalısınız.


7
Bu da beni etkileyen nokta. Birkaç statik ve durumsuz 'yardımcı' stil sınıfı iyi, ancak tüm sınıflarınızın% 25'ini statik olarak kullanıyorsanız, çabalarınızın bu durumla sınırlı olması muhtemel değildir.
Matthew Scharley

2
@MatthewScharley - Muhtemelen 4 ders aldı ve bunlardan 1'i Statik :)
Alexus

1
Bu tür stibcs kullanırsanız (singletons gibi), daha sonra daha fazla örnek oluşturmanın zor bir iş olabileceğine dikkat edin. Örneğin, bir dokümanı işleyen bir uygulama yapmak gibi daha sonra birden çok dokümanı yönetmek istediğinizde sorunlarla karşılaşırsınız.
Michel Keijzers

11

Yayınlanan cevaplar gerçekten çok iyi noktaları kapsıyor, ancak eksik gibi görünen bir cevap var:

Statik alanlar hiçbir zaman çöp toplanmaz.

Çok fazla bellek kısıtlaması olan bir uygulamanız varsa bu gerçekten önemlidir ve insanlar bir önbellek uygulamaya çalıştığında bu kalıp çok yaygın olabilir.

Statik fonksiyonlar neredeyse hiç de fena değil, ama herkes zaten bunu yeterince ayrıntılı olarak ele aldı.


10

IoC / DI'den aldığınız avantajlardan biri, sınıflar arasındaki etkileşimlerin çoğunun arayüzler arasında müzakere edilmesidir. Bu, ünite testini kolaylaştırır, çünkü arayüzler otomatik veya yarı otomatik olarak alay edilebilir ve bu nedenle parçaların her biri giriş ve çıkışlar için test edilebilir. Dahası, test edilemenin ötesinde, her şeyin arasına arabirim koymak mümkün olan en modüler koda sahip olmanıza izin verir - bağımlılıkları mahvettiğiniz için çok fazla endişe duymadan tek bir uygulamayı kolayca değiştirebilirsiniz.

C # 'nın metasınıfları olmadığı için, bir sınıf statik özellikleri kullanarak bir arayüz uygulayamaz, bu nedenle sınıfların statik özellikleri saf bir IoC / DI nesne modeli uygulamak için her türlü çabayı arttırır. Yani, onları test etmek için bir alay yaratamazsınız ve gerçek bağımlılıklar yaratmalısınız.

Eğer şirketiniz / projeniz IoC'ye yoğun bir şekilde yatırım yapıyorsa, bu elbette makul bir endişe ve yaşadığınız acı herkesin kazanması için. Mimari açıdan bakıldığında, şahsen hiçbir modelin mezara kadar takip edilmesi gerektiğini düşünmüyorum. Örneğin statik yöntemleri kullanarak uygulamanın mantıklı olduğu bazı şeyler var - örneğin, singleton tasarım stratejisi. Statik derslere daha az eğim var çünkü OO'nun avantajlarını yitirme eğiliminde olduklarını düşünüyorum, ancak bir kütüphane sınıfının bir motordan daha doğal bir ifadenin daha doğal bir ifadesi olduğu zamanlar vardır.


Yorum yapanlar bana elbette C # dilinde statik sınıflarda olması gereken uzatma yöntemlerini hatırlatıyor. Bu okunaklı ve en azından dilin genişliğinden yararlanmaya çalışıyorsanız, C # 'da saf IoC'nin ne kadar iyi çalışmadığının bir örneği.


1
Eğer bir sınıf doğru nedenlerden dolayı statik hale getirilirse ve örneğin uzatma yöntemleri gibi doğru bir şekilde uygulanırsa, dış bağımlılıkları olmayacak ve kendi kendine yetecekleri ve alay etmeleri gerekmeyecekleri için test edilebilirler. Arayüze duyulan gereksinim, saf bir IoC / DI projesi yürütmek için değil, bir iş gereksinimini en iyi şekilde doldurmak için tasarım gereksinimi tarafından yönlendirilmemeli midir?
Hayır,

1
Siz ve ben genel olarak, doğru iş için doğru aracı seçmeniz ve felsefe tarafından kelepçelenmemeniz gerektiği konusunda hemfikiriz. Bununla birlikte, saf IoC / DI projenizde iyi kurulmuş bir kültür varsa, geleneksel yukarıdan aşağıya bir çözümü IoC / DI'ye dönüştürmek kadar acı verir. Mühendislik, geçiş maliyetlerini göz önünde bulundurmalıdır. Bu arada, uzatma yöntemlerinin sizi oraya götüreceğini sanmıyorum. Statik sınıflarla IoCish davranışı için daha iyi bir çözüm, önişlemci direktifleriyle derleme zamanı arasında seçilen çoklu sınıflara sahip olmak olacağını düşünüyorum, C tarzı
jwrush 13:12

1
Er. Aptalım ben. HOLDİNG uzatma yöntemleri için statik bir sınıf demek istediniz, tabii ki bunları nasıl yapmanız gerektiği. Evet, elbette, bu amaç için statik bir sınıf istersiniz. Bu benim aklımdan çıktı: ve bu C # 'nin IoC için uygun olmadığını gösteriyor. :)
jwrush

Evet, haklısınız, mevcut bir projede mevcut bir kültür varsa, işlerin nasıl yapıldığının değiştirilmesine yardımcı olmaktan daha zarar verici olabilir.
Hayır,

5

Statik sınıflar bazen yanlış kullanılır ve şöyle olmalıdır:

  • Bir singleton (statik olmayan sınıfın yalnızca bir kez almak / oluşturmak için statik bir üyeye ve genel statik bir Örnek değişkenine sahip olduğu bir.
  • başka bir sınıfta bir yöntem (devletin önemli olduğu yer). Bu sınıftan veri kullanmayan bir üyeniz varsa, muhtemelen o sınıfın bir parçası olmamalıdır.

Aynı zamanda “yardımcı” işlevi ve yardımcı sınıfın bir parçası olabilir. Yardımcı sınıflar, yalnızca statik yöntemler içeren ve herhangi bir bağlam olmadan yardımcı işlevler olarak işlev gören sınıflardır.


@topomorto Sınıf, kurucusu tarafından birden çok nesne / örnekle sonuçlanan örneğiyle başlatılmamalı, ancak örneğe () ilk çağrısından sonra başlatılan her zaman aynı örneği döndüren özel bir yöntemle (normalde örnek ()) <başlatılmalıdır.
Michel Keijzers

@topomorto Ben sadece kontrol ettim ve tamamen haklısınız, sadece bazı üyeler statiktir (örnek değişkeni ve örnek işlevi). Buna göre cevabımı değiştireceğim; Bahsettiğin için teşekkürler.
Michel Keijzers

4

Statik metotların kullanımı iyidir ve programlamada haklı bir yere sahiptir. Mimarınız, statik yöntemleri tam olarak desteklemeyen bir test çerçevesine sahip gibi görünüyor. Eğer kodunuz daha büyük bir projenin parçasıysa, mimar kurallarına uymak önemlidir. Ancak, bu projenin uygun olduğunda statik yöntemleri kullanmaktan caydırmasına izin vermeyin.


1

Bir sınıfın tüm örneklerinde ortak olan şeyler için statik özellikler kullanıyorum. Ve sınıf nesnelerinin gruplarını almak için statik yöntemler kullanıyorum. Hiçbir şekilde bir uzman değilim ama bu benim için şu ana kadar çalışıyor.

PHP örneği:

class vendorData {
  private static $data_table = 'vendor_data'; // static property
  private $id; // instance property
  private $name; // instance property

  public function __construct($vendor_id) {
    if(!self::validId($vendor_id) ) { // static method
      return false; // id doesn't exist
    }
    $this->id = $vendor_id; // id has been validated
    $this->getProperties(); // object method
  }

  private static function validId($vendor_id) {
    // send db query to find if the id exists
    // return true/false;
  }

  private function getProperties() { // object method
    $sql = "SELECT * FROM `{self::$data_table}` // using static property
        WHERE `id` = {$this->id}"; // using object instance property
    // get resultset
    foreach($result as $property => $value) {
      $this->$property = $value; // object instance properties all set
    }
  }

  // and here
  public static function getBy($property,$value) { // static method to return object array
    $sql = "SELECT `id` FROM `{self::$data_table}` // using static property
      WHERE `$property` = '$value'";
    // send query, get $ids array
    $obj_array = array();
    foreach($ids as $id) {
      // create array of current class objects using special static keyword
      // meaning of static here is different than in property/method declarations
      $obj_array[$id] = new static($id);
    }
    return $obj_array;
  }
}

1

Onların sahip oldukları ilkelerin iyi olduğunu söyleyeceğim ancak (statik kullanmayın) ifadesi yanlış olabilir. Kod kapsamınız ne kadar? Eğer sayı yüksekse ve uygulamanızın ünite testi konusunda rahatsanız, sorun yok demektir. Değilse, kodu gözden geçirmenizi öneririm. Statik sınıfların sebebi olup olmadığını bulabilirsiniz, bir çok şeye bağlı olacaktır.


-3

Statik yöntemli sınıflar OOP prensiplerini kötüye kullanır. Bu zaten bir OOP değil, COP - sınıf odaklı programlama.

Nadiren net bir "kişiliğe" ( burada en sevdiğim insan metaforunu kullanıyorum ) veya kimliğe sahipler . Yani kim olduklarını bilmiyorlar. Tek başına bu nokta, bu kavramdan OOP'ta kurtulmak için yeterlidir, ancak bunlardan daha fazlası vardır.

Bir sonraki, ilk noktanın bir sonucudur. Bu sınıflar kim olduklarını bilmediklerinden büyükten büyüğe olma eğilimindedirler.

Üçüncüsü, kodunuzu kesinlikle sürdürülemez kılar. Kullanımı statik yöntemlerle gizli bağımlılıkları tanıtır . Her yere açılırlar ve sınıfınızda neler olduğunu asla bilemezsiniz. Bundan yalnızca yapıcı imzasına bakarak emin olamazsınız.

Yavaşça, ama kaçınılmaz olarak, gizli bağımlılıklar kötü kontrol edildiğinden kodunuz gittikçe daha az uyumlu hale geliyor. Görünmez görünüyorlar. Ve bir tane daha eklemek çok kolay! Herhangi bir yöntemin imzasını değiştirmek zorunda değilsiniz. Tek yapmanız gereken statik bir yöntem çağırmak. Ve ne çirkin bir kod izler ...

Tamam, muhtemelen çoktan tahmin etmişsindir. Sıkı kavrama, düşük yapışma özelliğine sahip bir elemandır. Bazı sınıfları kullanan çok fazla müşteri varsa, bağlantı daha da zorlaşmaktadır. Ve zaten yazılı bir sınıf veya sadece küçük düzeltme gerektiren bir yöntem kullanarak büyük bir baştan çıkarma var. Sadece bir yöntem bayrak parametresi.

Statik yöntemler yerine ne kullanılmalı? Benim önerim OOP. Neden denemiyorsun?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.