Tamamen statik sınıflara sahip olmak kötü bir fikir mi?


16

Daha büyük bir solo proje üzerinde çalışıyorum ve şu anda bir örnek oluşturmak için herhangi bir neden göremediğim birkaç dersim var.

Örneğin, şu anda zar sınıfım tüm verilerini statik olarak saklar ve tüm yöntemleri de statiktir. İlklendirmem gerekmiyor çünkü zar atmak ve yeni bir değer elde etmek istediğimde, sadece kullanıyorum Dice.roll().

Ben sadece böyle bir ana işlevi olan birkaç benzer sınıfları var ve ben (bir oyuncu hareket ve ne mevcut dönüş gibi tüm olaylardan sorumlu olacak "denetleyici" sınıf bir tür üzerinde çalışmaya başlamak üzereyim ve bu sınıf için aynı fikri takip edebileceğimi buldum. Hiç bu belirli sınıflar için birden fazla nesne oluşturmayı planlamıyorum, bu yüzden onları tamamen statik hale getirmek kötü bir fikir olur mu?

Java söz konusu olduğunda bunun "kötü uygulama" olarak kabul edilip edilmediğini merak ediyordum. Gördüğüm kadarıyla, topluluk bu konuda biraz bölünmüş gibi görünüyor mu? Her neyse, bu konuda biraz tartışmayı çok isterim ve kaynaklara bağlantılar da harika olurdu!


1
Programınız tamamen prosedürel ise. Neden Java'yı seçtiniz?
Laiv

12
Bu sınıflar için birim testleri yazmayı deneyin ve insanların neden statik duruma erişen statik yöntemleri sevmediğini anlayacaksınız.
Joeri Sebrechts

@Laiv Hala programlama konusunda yeniyim, yaklaşık bir yıl C ++, bu sömestr bir Java dersi alıyorum ve özellikle grafik kütüphanelerinde Java'yı daha çok sevmeye başlıyorum.
HexTeke


5
Statik sınıflarla ilgili. Statik yöntemler safsa (hiçbir durumu tutmayın, girdi bağımsız değişkenleri ve bir dönüş türü vardır). Endişelenecek bir şey yok
Laiv

Yanıtlar:


20

Gerçekten statik olan statik sınıflarda yanlış bir şey yoktur . Yani, yöntemlerin çıktısının değişmesine neden olacak içsel bir durum söz konusu değildir.

Eğer Dice.roll()sadece 1 ila 6 arasında yeni bir rastgele sayı dönüyor, bu durumu değiştirmiyor. Verilen bir Randomörneği paylaşıyor olabilirsiniz , ancak tanım gereği bir durum değişikliğinin, çıktının her zaman iyi, rastgele olacağını düşünmüyorum. Ayrıca diş açmaya karşı güvenlidir, bu nedenle burada sorun yoktur.

Sıklıkla özel bir kurucu ve statik üyeleri olan son "Yardımcı" veya diğer yardımcı program sınıflarını görürsünüz. Özel kurucu mantık içermez ve yalnızca birisinin sınıfı örneklemesini önlemeye yarar. Son değiştirici, sadece bunun türetmek isteyeceğiniz bir sınıf olmadığı fikrini getirir. Sadece bir yardımcı sınıftır. Düzgün yapılırsa, kendileri statik ve nihai olmayan singleton veya diğer sınıf üyeleri olmamalıdır.

Bu yönergelere uyduğunuz ve singleton yapmadığınız sürece, bununla ilgili kesinlikle yanlış bir şey yoktur. Bir denetleyici sınıfından bahsediyorsunuz ve bu neredeyse kesinlikle durum değişiklikleri gerektirecek, bu yüzden sadece statik yöntemleri kullanmamanızı tavsiye ederim. Statik bir yardımcı program sınıfına çok güvenebilirsiniz, ancak bunu statik bir yardımcı program sınıfı yapamazsınız .


Bir sınıf için durum değişikliği nedir ? Tanım olarak belirsiz olmayan ve bu nedenle dönüş değeri sık sık değiştiğinden, rastgele sayıları bir saniyeliğine hariç tutalım.

Saf bir işlev deterministik olan bir işlevdir, yani belirli bir girdi için bir ve tam olarak bir çıktı alırsınız. Statik yöntemlerin saf işlevler olmasını istiyorsunuz. Java'da durumu korumak için statik yöntemlerin davranışını değiştirmenin yolları vardır, ancak neredeyse hiç iyi fikir değildir. Bir yöntemi statik olarak bildirdiğinizde , tipik programcı yarasanın hemen dışında saf bir işlev olduğunu varsayar. Beklenen davranışlardan sapmak, genel olarak konuşursak ve programınızda hatalar yaratma eğiliminizdir.

Singleton, olabildiğince "saf işlev" in tersi gibi statik yöntemler içeren bir sınıftır. Tek bir statik özel üye, tam olarak bir örnek olmasını sağlamak için kullanılan sınıfa dahili olarak tutulur. Bu en iyi uygulama değildir ve daha sonra birkaç nedenden dolayı başınızı belaya sokabilir. Ne hakkında konuştuğumuzu bilmek için, işte basit bir singleton örneği:

// DON'T DO THIS!
class Singleton {
  private String name; 
  private static Singleton instance = null;

  private Singleton(String name) {
    this.name = name;
  }

  public static Singleton getInstance() {
    if(instance == null) {
      instance = new Singleton("George");
    }
    return instance;
  }

  public getName() {
    return name;
  }
}

assert Singleton.getInstance().getName() == "George"

7
Eğer bir çift altı yuvarlandığında ne olduğunu test etmek istiyorum, ben statik bir rastgele sayı üreteci ile statik sınıf var gibi burada sıkışmış. Yani hayır, Dice.roll()“küresel devlet yok” kuralı için geçerli bir istisna değildir.
David Arno

1
@HexTeke Yanıt güncellendi.
Neil

1
@DavidArno Doğru, ancak sanırım tek bir çağrıyı test edersek gerçekten başımız belada random.nextInt(6) + 1. ;)
Neil

3
@Neil, özür dilerim, kendimi çok iyi açıklamadım. Rastgele sayı dizisini test etmiyoruz, diğer testleri desteklemek için bu diziyi etkiliyoruz. Eğer RollAndMove()bir çift altı tedarik ettiğimizde bu ruloları tekrar test edersek, bunu yapmanın en kolay, en sağlam yolu ya Dicerastgele sayıyı üretmektir. Ergo, Dicestatik rastgele bir jeneratör kullanarak statik bir sınıf olmak istemez.
David Arno

12
Güncellemeniz bu konuyu kafasına vuruyor: statik yöntemler deterministik olmalı; yan etkileri olmamalıdır.
David Arno

9

Bir staticsınıfın sınırlamalarına bir örnek vermek gerekirse, oyuncularınızdan bazıları kalıp atışlarında hafif bir bonus almak isterse ne olur? Ve büyük paralar ödemeye hazırlar! :-)

Evet, başka bir parametre ekleyebilirsiniz, bu nedenle Dice.roll(bonus),

Daha sonra D20'lere ihtiyacınız var.

Dice.roll(bonus, sides)

Evet, ancak bazı oyuncuların "üstün yetenekli" başarıları vardır, böylece asla "beceremezler" (bir rulo 1).

Dice.roll(bonus, sides, isFumbleAllowed).

Bu dağınık oluyor, değil mi?


Bu soruya dik olarak görünüyor, bu statik yöntemler veya normal yöntemler olup olmadığını onun elde dağınık
jk.

4
@jk, sanırım onun amacını anladım. Daha fazla dices türü düşündüğünüzde bir Dice statik sınıfına sahip olmak mantıklı değildir. Bu durumda, farklı zar nesnelerine sahip olabiliriz, onları iyi OOP uygulamaları ile modelleyebiliriz.
Dherik

1
@TimothyTruckle Tartışmayacağım, tüm söylediğim bu cevabın aslında soruyu cevaplamıyor olması, çünkü bu tür bir kapsam sürünmesinin statik ya da değil yöntemiyle ilgisi yoktur.
nvoigt

2
@nvoigt "Buna itiraz etmiyorum" - Evet, biliyorum. Bir OO dilinin en güçlü özelliği polimorfizmdir . Ve statik erişim etkili bir şekilde hiç bu kullanmasını engeller. Ve haklısın: Statik erişim de new Dice().roll(...)düşünülmeli . Sadece bu bağımlılığı enjekte edersek yararlanırız . Dice.roll(...)
Timothy Truckle

2
@jk fark her çağrıda staticdağınıklık olur ve her bilgi için gerekli bilgi gereklidir, bu yüzden tüm uygulama üzerinde küresel sıçraması alır. Bir OOP yapısında, sadece yapıcı / fabrikanın dağınık olması gerekir ve bu kalıbın detayları kapsüllenir. Bundan sonra, polimorfizm kullanın ve sadece arayın roll(). Açıklığa kavuşturmak için bu cevabı düzenleyebilirim.
user949300

3

Bir Dice sınıfının özel durumunda, statik yerine örnek yöntemlerinin kullanılmasının testi önemli ölçüde kolaylaştırdığını düşünüyorum.

Bir Zar örneği (örneğin bir Oyun sınıfı) kullanan bir şeyi test etmek istiyorsanız, o zaman testlerinizden, her zaman sabit bir değer dizisi döndüren bir tür zar çiftini enjekte edebilirsiniz. Testiniz, oyunun bu zar atışları için doğru sonuca sahip olup olmadığını kontrol edebilir.

Ben bir Java geliştiricisi değilim ama tamamen statik bir Dice sınıfıyla bunu yapmak çok daha zor olacağını düşünüyorum. Bkz. Https://stackoverflow.com/questions/4482315/why-does-mockito-not-mock-static-methods


Sadece kayıtlar için: Java'da , bayt kodunu değiştirerek statik bağımlılıkları değiştirmek için PowerMock'umuz var . Ama bunu kullanmak kötü tasarıma teslim olmaktır ...
Timothy Truckle

0

Bu aslında Monostate paterni olarak bilinir ve burada her örnek (ve hatta "örnek olmayan") durumlarını paylaşır. Her üye bir sınıf üyesidir (örnek üye yok). Genellikle tek bir sorumluluk veya gereksinimle ilgili bir dizi yöntem ve sabitleri bir araya getiren ancak çalışmak için bir duruma ihtiyaç duymayan "araç seti" sınıflarını uygulamak için kullanılırlar (tamamen işlevseldirler). Aslında, Java bazılarıyla birlikte gelir (örneğin, Math ).

Biraz konu dışı: Nadiren VisualBasic anahtar kelime adlandırma ile katılıyorum, ama bu durumda, bence sharedkesinlikle daha net ve anlamsal olarak daha iyi (o olduğu paylaşılan daha sınıfın kendisi ve örneklerinin tümü arasında) staticyaşam döngüsü sonra (kalıntılardan beyan ettiği kapsamın).

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.