Java Static olan global değişkenler encapsulation ilkesine göre get ve set metodlarına ihtiyaç duyar mı?

BeyazEsya

Picopat
Katılım
1 Mayıs 2021
Mesajlar
184
Daha fazla  
Cinsiyet
Erkek
Meslek
Öğrenci
Merhaba, static olan global değişkenler encapsulation ilkesine göre get ve set metodlarına ihtiyaç duyar mı? Örneğin kapsülleme ilkesinden faydanalabilmek için nitelikleri private yaparız ve get ile set metodları kullanırız. Peki static olarak tanımlanan bir değişken için (Örneğin bir online oyunda oyuncu sayısını tutsun.) kapsülleme ilkesine uymak gerekir mi? Yani get ve set metodları oluşturmak gerekir mi?
 
Son düzenleyen: Moderatör:
Yani neden değerinin değiştirilmesi pek tercih edilmiyor?
(global degerin degismesi)

Encapsulation yok. OO prensiplerine aykiri. Ipini koparak global variable update ederse debug etmek ve okumak zor olur. Unit test yazmak iskence olur.

Multithread uygulamada ayni variable i update ederken race condition olusturursun, eger gerekli concurrency onlemlerini almayip encapsulation yapmadiysan.

Burada problem deger degistirmek degil, global variable degeri degistirmek.
Math.PI = 3.1415... -> Bunu degistirmezsin zaten.
Degistireceksen de constant degildir, o halde static tanimlamazsin; tanimladiysan da yanlis yaptin.
 
Temel sorun statik tanımlanan tiplerin, değişkenlerin nesneye yönelik olmaması. Esneklik ve genişletilebilirliği zorlaştırması. Nesneye yönelik programlamanın en büyük arzusu birbirinden bağımsız nesneler, sınıflar üretmektir. Geliştirme yaparken de var olan sınıfı düzenlemek değil de onu kullanan ya da ondan türetilmiş yeni sınıflar ile bunu sağlamaktır. Çok biçimlilik de tam olarak bunu sağlamak için var.

Eğer bir değişkeni sınıfı statik olarak tanımlıyorsanız ona doğrudan erişmiş oluyorsunuz. Yani diğer sınıflardan yazdığınız kod da o statik sınıfa bağımlı hale gelmiş oluyor. Daha da kötüsü o sınıfın statik haline bağımlı hale gelmiş oluyor. O değişkeni sonradan normal sınıf değişkenine, alanına çevirmek isterseniz bu statik değişkeni kullanan sınıfları da düzenlemeniz gerekir. Tek kişi kod yazarken bu sorun değil fakat farklı kütüphaneleri geliştiren farklı ekipler olduğunda sorun. İdealde istenen değişiklik değil geliştirme yapılması. Yeni sınıflarla tiplerle sistemlerin genişletilmesi.

Peki bu statik kullanmadan nesneye yönelik olarak nasıl yapılabilir. Oyuncu sayısını tutan Game sınıfı normal sınıf olarak yazılır. Bu nesneden sadece bir adet oluşturulacak şekilde bu sınıfa ihtiyaç duyacak diğer sınıflara bağlanır. Burada Game sınıfının kendi içine de Singleton pattern'ini uygulayabilirsiniz yani bu sınıf kendi içinde sadece 1 adet nesne oluşturulacak şekilde de tanımlanabilir ama bu da nesne oluşturma mantığını, sınıfın kendi işini yapma mantığı ile birleştireceği için Separation of Concerns prensibine test düşecektir [kaynak]. İdealde her sınıf kendi işini yapmalı nesne bağlantıları harici bir sistem tarafından yapılmalıdır. Java'da Spring kütüphanesi burada devreye giriyor. Bu noktada Dependency Injection, Inversion of Control gibi programlamanın kendisi ile ilgili değil yazılım mimarisi ile ilgili kavramlarla karşılaşıyoruz ki bence çok gerekmedikçe hiçbir uygulamayı bu seviyeye taşımamak gerekir. EJB kadar olmasa da belli ölçüde hayattan soğutur. Programlama ile değil bürokrasi ile uğraşmaya başlarsınız.

Peki ne yapmalı? Kurumsal için cevap Spring kaçarı yok :D . Bireyselde mümkün olduğunca kallavi kütüphanelere bulaşmadan OOP'a uygun yazayım diyorsanız şöyle olabilir. Game sınıfı ayrı olur sadece kendi işini yapar. Verdiğiniz örneğe göre sadece oyuncu sayısını tutar. Bu sınıftan sadece bir tane oluşturup ilgili diğer sistemlere bağlantısını yapacak ayrı bir sınıf olur. Buna System ya da Runtime diyebiliriz. Sadece nesne üretip diğer sınıflara bağlamak ile sorumlu kendi çok çok basit Spring uyarlamamız diyebiliriz. Game sınıfındaki oyuncu sayısına erişmek isteyen sınıflara oluşturulan tek bir Game nesnesini yine Runtime sınıfı verir. Örneğin oyuncu sayısını oyun içi ekranda yani HUD'da göstereceksek ayrı bir HUD sınıfımız varsa buna bağlantıyı Runtime sağlayabilir. Yani aşağı yukarı şöyle:

Java:
class Game {
  // OyuncuSayisi ile ilgili tum islemler Game sinifda
  // Bu nedenle OyuncuSayisi public degil
  // Sorumluluklarin ayrilmasi prensibi (SoC)
  private int OyuncuSayisi;

  public int GetOyuncuSayisi() {
    return OyuncuSayisi;
  }

  public void OyuncuBaglandi() {
    OyuncuSayisi++;
  }
}

class Runtime {
  // Runtime sadece nesne üretimi ve birbiri ile bağlantısı yapıyor
  Game gameInstance;
  HUD hudInstance;
 
  public Runtime() {
    gameInstance = new Game();
    hudInstance = new HUD(gameInstance);
  }

  public Game GetGameInstance() {
    return gameInstance;
  }

  public HUD GetHudInstance() {
    return hudInstance;
  }
}

class HUD {
  Game game;
 
  // contructor tabanli dependency injection
  public HUD(Game game) {
    this.game = game;
  }
 
  public void OyuncuSayisiBas() {
    System.out.println("Toplam Oyuncu " + game.GetOyuncuSayisi());
  }
}

class Main {
  public static void main(String[] args) {
    var runtime1 = new Runtime();
    var game1 = runtime1.GetGameInstance();
    var hud1 = runtime1.GetHudInstance();
    hud1.OyuncuSayisiBas();
    game1.OyuncuBaglandi();
    hud1.OyuncuSayisiBas();
  }
}

Burada her sınıf sadece kendi işini yapıyor. Game sınıfının kendisinde tek bir tane olma zorlaması yok. Statik ya da Singleton kullansaydık böyle olacatı. Bu sistemde sırf bu işle yani hangi nesneden kaçtane olacak nasıl bağlayacak sorularından sorumlu Runtime sınıfı var. Şu an istesek mainde birden fazla Runtime da oluşturup kullanabiliriz. Runtime'ın kendisinde bu bağlantıları düzenleyebiliriz. Böylece hem sınıflar sadece kendi işlerini yaptığı için kodun takibi ve bakımı daha kolay oldu hem de birbirlerine olan bağlantıları harici bir şekilde yapıldığı için daha esnek bir hale geldi. İdealde bu bağlantıların da esneklik sağlaması adına interface kullanılarak yapılması daha uygun olur ama artık o kadar da bürokrasiye girmek şu aşamada kodu bu halinden daha karışık hale getirir.

Spring bu bağlantıları sizin uygulama kodunuzdan ayırıyor. Nesne üretimini kendi yapıyor. Bağlantıları da Spring kullanarak onun üzerinden sağlıyorsunuz. Aynı Interface'den türetilmiş sınıfları XML editleyerek kodu tekrar derlemeden birbiri yerine kullanabiliyorsunuz. Bizim Runtime'da yapmaya çalıştığımızın çok çok daha gelişmişi yani. Bu nedenle böyle ortak ihtiyaçlar kurumsal projelerde çok büyük mesele olduğu için bu ve çok daha fazlası için Spring gibi kütüphaneler kullanıyorlar.
 
Son düzenleme:

Geri
Yukarı