Java'da Hangi Stil Daha İyi (Örnek Değişkeni Karşılığı Değer)


32

Sınıflarımdaki bazı yöntemlerde ortak verileri kullanmam gerektiğinde, bu iki yoldan hangisinin kullanılacağına karar vermek için kendimi sık sık buluyorum. Daha iyi bir seçim ne olurdu?

Bu seçenekte, ek değişkenler bildirmek zorunda kalmama gerekliliğinden kaçınmak ve ayrıca yöntem parametrelerini tanımlamaktan kaçınmak için bir örnek değişken oluşturabilirim, ancak bu değişkenlerin nerede başlatıldığını / değiştirildiğini çok açık olmayabilir:

public class MyClass {
    private int var1;

    MyClass(){
        doSomething();
        doSomethingElse();
        doMoreStuff();
    }

    private void doSomething(){
        var1 = 2;
    }

    private void doSomethingElse(){
        int var2 = var1 + 1;
    }

    private void doMoreStuff(){
        int var3 = var1 - 1;
    }
}

Ya da sadece yerel değişkenleri somutlaştırmak ve bunları argüman olarak iletmek?

public class MyClass {  
    MyClass(){
        int var1 = doSomething();
        doSomethingElse(var1);
        doMoreStuff(var1);
    }

    private int doSomething(){
        int var = 2;
        return var;
    }

    private void doSomethingElse(int var){
        int var2 = var + 1;
    }

    private void doMoreStuff(int var){
        int var3 = var - 1;
    }
}

Cevap her ikisinin de doğru olması durumunda hangisi daha sık görülür / kullanılır? Ayrıca, her seçenek için ek artılar / eksiler sağlayabilirseniz, çok değerli olacaktır.



1
Kimsenin henüz değişken sonuçlara ara sonuç vermenin, bu değişkenler için iş parçacığı arasındaki çekişme olasılığı nedeniyle eşzamanlılığı daha da zorlaştırabileceğine işaret etmediğini sanmıyorum.
sdenham

Yanıtlar:


107

Bunun henüz bahsetmediğine şaşırdım ...

Bu var1aslında nesnenin durumunun bir parçası olup olmamasına bağlı .

Her iki yaklaşımın da doğru olduğunu ve bunun sadece bir stil meselesi olduğunu varsayıyorsunuz. Hatalısınız.

Bu tamamen nasıl düzgün bir şekilde modelleneceği ile ilgilidir.

Benzer şekilde, nesnenin durumunu değiştirmek içinprivate örnek yöntemler mevcuttur . Yöntemin yaptığı şey bu değilse, öyle olmalı .private static


7
@mucaho: Bununla bir transientilgisi yok, çünkü nesneyi seri hale getirme gibi bir şey yaptığınızda kurtarılan nesnenin bazı kısımlarında olduğu gibi kalıcı durum transienthakkında . Örneğin, bir ArrayList'in destek deposu, ArrayList'in durumu için son derece önemli olsa da, çünkü bir ArrayList'i seri hale getirirken, yalnızca boş alan değil, gerçek ArrayList öğelerini tutan destek deposunun bir bölümünü kaydetmek istersiniz. Sonunda daha fazla eleman eklemeleri için ayrılmıştır. transient
user2357112,

4
Cevabın eklenmesi - eğer var1birkaç yönteme ihtiyaç duyulursa fakat durumun bir parçası olmasaydı MyClass, var1bu yöntemleri kullanmak için başka bir sınıfa koyma zamanı gelebilir MyClass.
Mike Partridge

5
@CandiedOrange Burada doğru modelleme hakkında konuşuyoruz. "Nesnenin durumunun bir parçası" derken, koddaki değişmez parçalar hakkında konuşmuyoruz. Kavramsal olarak bir devlet nosyonunu tartışıyoruz , kavramları doğru bir şekilde modellemek için nesnenin durumu ne olmalı . "Yararlı ömür" muhtemelen bu konuda en büyük karar verici faktördür.
jpmc26

4
@CandiedOrange Sonraki ve Önceki açıkçası genel yöntemlerdir. Eğer var1 değeri yalnızca bir dizi özel yöntemle alakalıysa, açıkça nesnenin kalıcı durumunun bir parçası değildir ve bu nedenle argümanlar olarak aktarılmalıdır.
Taemyr

2
@CandiedOrange İki yorumdan sonra ne demek istediğinizi netleştirdiniz. İlk cevabınızda kolayca sahip olabileceğinizi söylüyorum. Ayrıca, evet, sadece nesneden daha fazlası olduğunu unuttum; Bazen özel örnek yöntemlerinin bir amacı olduğuna katılıyorum. Aklıma hiçbir şey getiremedim. EDIT: Sadece bana cevap veren ilk kişi olmadığını fark ettim. Benim hatam. Bir cevabın neden bir cüruf, bir cümle, cevapsız olduğu, sonra da bir şeyler açıklandığı için kafam karışmıştı.
Fon Monica'nın Davası,

17

Hangisinin daha yaygın olduğunu bilmiyorum, ama ben her zaman ikincisini yaparım. Veri akışını ve ömrünü daha net bir şekilde iletir ve sınıfınızın her bir örneğini başlatma sırasında yalnızca ilgili ömrü olan bir alanla şişirmez. Eskiden birinin kafa karıştırıcı olduğunu ve kod incelemesini önemli ölçüde daha zorlaştırdığını söyleyebilirim, çünkü herhangi bir yöntemin değişebileceğini düşünmem gerekiyor var1.


7

Azaltmak gerekir Değişkenlerinizin kapsamını mümkün olduğunca (ve makul). Sadece yöntemlerde değil, genel olarak da.

Sorunuz için bu, değişkenin nesnenin durumunun bir parçası olup olmamasına bağlı olduğu anlamına gelir. Eğer öyleyse, onu bu kapsamda, yani bütün nesneyi kullanmakta sorun yoktur. Bu durumda ilk seçenek ile gidin. Eğer değilse, değişkenlerin görünürlüğünü ve dolayısıyla genel karmaşıklığı azalttığı için ikinci seçeneğe geçin.


5

Java'da Hangi Stil Daha İyi (Örnek Değişkeni Karşılığı Değer)

Başka bir stil var - bağlam / durum kullanın.

public static class MyClass {
    // Hold my state from one call to the next.
    public static final class State {
        int var1;
    }

    MyClass() {
        State state = new State();
        doSomething(state);
        doSomethingElse(state);
        doMoreStuff(state);
    }

    private void doSomething(State state) {
        state.var1 = 2;
    }

    private void doSomethingElse(State state) {
        int var2 = state.var1 + 1;
    }

    private void doMoreStuff(State state) {
        int var3 = state.var1 - 1;
    }
}

Bu yaklaşımın birçok faydası vardır. Devlet nesneleri, örneğin nesneden bağımsız olarak değişebilir ve geleceğe daha fazla sıkıntı yaratabilir.

Bu aynı zamanda bazı detayların çağrılar arasında korunması gereken dağıtılmış / sunucu sisteminde de iyi çalışan bir kalıptır. Kullanıcı ayrıntılarını, veritabanı bağlantılarını vb. stateNesnede saklayabilirsiniz .


3

Yan etkileri hakkında.

var1Devletin bir parçası olup olmadığını sormak bu sorunun noktasını kaçırıyor. Tabii var1devam ederse, bunun bir örneği olması gerekir. Kalıcılığa ihtiyaç duyulup duyulmadığına bakmak için her iki yaklaşım da yapılabilir.

Yan etki yaklaşımı

Bazı örnek değişkenler yalnızca aramadan aramaya özel yöntemler arasında iletişim kurmak için kullanılır. Bu tür bir örnek değişkeni varlığın dışına çıkarılabilir, ancak böyle olması gerekmez. Bazen işler onlarla daha açık. Ancak bu risksiz değil.

İki farklı özel kapsamda kullanıldığı için bir değişkenin kapsamı dışında kalmasına izin veriyorsunuz. Bunu yerleştirdiğiniz kapsamda gerekli olduğundan değil. Bu kafa karıştırıcı olabilir. "Kürekler kötüdür!" kafa karıştırıcı. Bu işe yarayabilir ama sadece iyi ölçeklendirilmez. Sadece küçük çalışır. Büyük nesneler yok. Kalıtım zinciri yok. Yo yo etkisi yapmayın .

Fonksiyonel yaklaşım

Şimdi, var1devam etmeli olsa bile, hiçbir şey kullanmak zorunda olduğunuzu söylemez, açık çağrılar arasında korunmak istediğiniz duruma gelmeden önce alabileceği her geçici değer için. Bu hala bir ayar yapabilirsiniz anlamına gelirvar1 daha işlevsel yöntemlerden başka şey kullanarak örnek oluşturabileceğiniz .

Yani devletin bir parçası olsun ya da olmasın, yine de her iki yaklaşımı da kullanabilirsiniz.

Bu örneklerde 'var1' öylesine kapsüllenmiş ki hata ayıklayıcınızdan başka hiçbir şey olmadığını biliyor. Sanırım bunu bilerek yaptın çünkü bizi önyargılı etmek istemiyorsun. Neyse ki hangisi olduğu umurumda değil.

Yan etki riski

Bu, sorunuzun nereden geldiğini biliyorum. Sefil altında çalıştım yo yo 'mutasyon bir örnek birden yöntemlerde birden çok düzeyde değişken ve sincap onu izlemeye çalışıyorum gitmiş olduğunu ing miras. Bu risk.

Bu beni daha işlevsel bir yaklaşıma iten acıdır. Bir yöntem bağımlılıklarını ve çıktılarını imzasında belgeleyebilir. Bu güçlü ve net bir yaklaşımdır. Ayrıca, özel metodu ne geçtiğini değiştirerek sınıf içinde daha tekrar kullanılabilir hale getirmenizi sağlar.

Yan etkilerin tersi

Aynı zamanda sınırlayıcı. Saf fonksiyonların yan etkisi yoktur. Bu iyi bir şey olabilir ama nesneye yönelik değil. Nesne yönlendirmesinin büyük bir kısmı, yöntemin dışındaki bir içeriğe gönderme yeteneğidir. Bunu burada tüm dünyayı ve dünyayı sızdırmadan yapmak OOP'un gücüdür. Globalin esnekliğini alıyorum ama sınıfta hoş bir şekilde yer alıyor. İsterseniz bir yöntemi çağırabilir ve her örnek değişkenini aynı anda mutasyona uğrayabilirim. Bunu yaparsam, en azından bu yöntemi ne yaptığını açıklığa kavuşturan bir isim vermek zorunda olduğum için insanlar böyle olunca şaşırmayacaklar. Yorumlar da yardımcı olabilir. Bazen bu yorumlar "posta koşulları" olarak resmileştirilir.

İşlevsel özel yöntemlerin olumsuz yönü

İşlevsel yaklaşım bazı bağımlılıkları netleştirir. Tamamen işlevsel bir dilde olmadığınız sürece gizli bağımlılıkları ekarte edemez. Bilmiyorsunuz, sadece bir yöntem imzasına bakarak, kodunun geri kalanında sizden bir yan etki gizlemediğini biliyorsunuz. Sen yapmıyorsun

Şartlandırma sonrası

Siz ve takımdaki herkes, yan etkileri (ön / post koşullar) yorumlardaki güvenilir bir şekilde belgeliyorsa, işlevsel yaklaşımdan elde edilen kazanç çok daha azdır. Evet biliyorum, hayal kuruyorum.

Sonuç

Şahsen, eğer yapabilirsem, her iki durumda da işlevsel özel yöntemlere yöneliyorum, ama dürüst olmak gerekirse, bunun nedeni, koşullu yan etki öncesi / sonrası yorumların, eski olduklarında veya yöntemler sıra dışı çağrıldığında derleyici hatalarına neden olmamasıdır. Gerçekten yan etkilerin esnekliğine ihtiyacım yoksa, sadece işlerin işe yaradığını bilmek istiyorum.


1
"Bazı örnek değişkenler yalnızca aramadan aramaya özel yöntemler arasında iletişim kurmak için kullanılır." Bu bir kod kokusu. Örnek değişkenleri bu şekilde kullanıldığında, sınıfın çok büyük olduğunun bir işaretidir. Bu değişkenleri ve yöntemleri yeni bir sınıfa çıkarın.
kevin cline

2
Bu gerçekten bir anlam ifade etmiyor. OP iken olabilir fonksiyonel paradigmada kod yazmak (ve bu genellikle iyi bir şey olurdu), yani açıkçası sorunun bağlamı değildir.
OP'ye

@kevincline OP'in örneğinde sadece bir örnek değişken ve 3 yöntem var. Temel olarak, zaten yeni bir sınıfa çıkarıldı. Örneğin yararlı bir şey yapması değil. Sınıf büyüklüğünün, özel yardımcı yöntemlerin birbirleriyle nasıl iletişim kurduğuyla ilgisi yoktur.
MagicWindow

@ jpmc26 OP, var1paradigmaları değiştirerek durum değişkeni olarak saklamaktan kaçınabileceklerini zaten göstermiştir . Sınıf kapsamı, yalnızca durumun depolandığı yerde DEĞİLDİR. Aynı zamanda çevreleyen bir kapsamdır. Bu, sınıf değişkenine değişken koymak için iki olası motivasyon olduğu anlamına gelir. Bunu yalnızca ekteki kapsam için yapıyor ve devletin kötülük olmadığını iddia edebilirsiniz, ancak bunun aynı zamanda kötülük olan bir ariteyle ticaret olduğunu söylüyorum . Bunu biliyorum çünkü bunu yapan kodu saklamak zorunda kaldım. Bazıları iyi yapıldı. Bazıları kabus gibiydi. İkisi arasındaki çizgi devlet değil. Bu okunabilirlik.
MagicWindow

Durum kuralı okunabilirliği artırır: 1) işlemlerin sonuçlarının durum gibi görünmesini engellemekten kaçının 2) yöntemlerin bağımlılıklarını gizlemekten kaçının. Bir yöntemin ariteliği yüksekse, o zaman ya indirgenemez bir şekilde ve gerçekten de o yöntemin karmaşıklığını temsil eder ya da mevcut tasarımın gereksiz karmaşıklığı vardır.
sdenham

1

İlk değişken sezgisel değil ve benim için potansiyel olarak tehlikeli görünüyor (birinin özel yönteminizi herkese açık hale getirmesinin ne nedenle olduğunu düşünün).

Değişkenlerinizi sınıf yapımı üzerine başlatmayı ya da argüman olarak iletmeyi tercih ederim. İkincisi, işlevsel deyimleri kullanma ve onu içeren nesnenin durumuna dayanma seçeneği sunar.


0

Nesne durumu hakkında ve ikinci yöntemin ne zaman tercih edildiğinden bahseden cevaplar zaten var. İlk kalıp için ortak bir kullanım örneği eklemek istiyorum.

İlk desen, sınıfınızın yaptığı tek şey bir algoritmayı kapsıyorsa mükemmel bir şekilde geçerlidir . Bunun bir kullanım durumu, algoritmayı tek bir metoda yazdıysanız çok büyük olacağıdır. Böylece onu daha küçük yöntemlere ayırıyorsunuz, bir sınıf haline getiriyor ve alt yöntemleri özel yapıyorsunuz.

Şimdi algoritmanın tüm halini parametreler yoluyla geçirmek yorucu olabilir, böylece özel alanları kullanırsınız. Aynı zamanda ilk paragraftaki kurala da uygundur, çünkü temelde bu bir durumdur. Sadece bunun için özel alanlar kullanıyorsanız, algoritmanın önemsiz olmadığını akılda tutmanız ve doğru bir şekilde belgelemeniz gerekir . Bu çoğu zaman bir sorun olmamalı, ancak sizi ısırmaya başlayabilir.


0

Bir şeyler yapan bir örnek deneyelim. Bu javascript java değil çünkü beni affet. Mesele aynı olmalı.

Https://blockly-games.appspot.com/pond-duck?lang=en adresini ziyaret edin , javascript sekmesini tıklayın ve şunu yapıştırın:

hunt = lock(-90,1), 
heading = -135;

while(true) {
  hunt()  
  heading += 2
  swim(heading,30)
}

function lock(direction, width) {
  var dir = direction
  var wid = width
  var dis = 10000

  //hunt
  return function() {
    //randomize() //Calling this here makes the state of dir meaningless
    scanLock()
    adjustWid()
    if (isSpotted()) {
      if (inRange()) {
        if (wid <= 4) {
          cannon(dir, dis)
        }
      }
    } else {
      if (!left()) {
        right()
      }
    }
  }

  function scanLock() {
    dis = scan(dir, wid);
  }

  function adjustWid() {
    if (inRange()) {
      if (wid > 1)
        wid /= 2;
    } else {
      if (wid < 16) {
        wid *= 2; 
      }
    }
  }

  function isSpotted() {
    return dis < 1000;
  }

  function left() {
    dir += wid;
    scanLock();
    return isSpotted();
  }

  function right() {
    dir -= wid*2;
    scanLock();
    return isSpotted()
  }

  function inRange() {
    return dis < 70;
  }

  function randomize() {
    dir = Math.random() * 360
  }
}

Bunu fark etmeli dir, widve disçok etrafında geçirilen sakın. Ayrıca, lock()döndüren işlevdeki kodun sözde kod gibi göründüğüne dikkat etmelisiniz . Peki bu gerçek kod. Oysa okumak çok kolay. Geçiş ve atama ekleyebiliriz, ancak bu sözde kodda asla görmeyeceğiniz bir karmaşa katacaktır.

Bu üç değişkenin kalıcı durum olması nedeniyle ödev vermenin ve geçmenin iyi olmadığını iddia etmek istiyorsanız, dirher döngüye rastgele bir değer atanan bir yeniden tasarım düşünün . Şimdi kalıcı değil mi?

Tabii, şimdi şimdi dirkapsamı düşebiliriz ancak sözde kodumuzu geçip ayarlayarak karıştırmaya mecbur olmadan.

Yani hayır, devlet neden geçip geri dönmek yerine yan etkileri kullanmaya ya da kullanmaya karar verdiğini belirlemez. Yan etkiler tek başına da kodunuzun okunamadığı anlamına gelmez. Sen alamadım saf fonksiyonel kod yararları . Fakat iyi isimler, iyi isimlerle okumak gerçekten güzel olabilirler.

Bu, kabus gibi bir spagetti ye dönüşemeyecekleri anlamına gelmez. Ama sonra ne yapamaz?

Mutlu ördek avı.


1
İç / dış fonksiyonlar OP'nin tanımladığından farklı bir paradigmadır. - Bir dış işlev kontra içindeki yerel değişkenler arasındaki değişimin iç işlevlere argümanlar ilettiğini kabul ediyorum, bir sınıf kontra üzerindeki özel değişkenlere benzer argümanlar özel işlevlere geçti. Bununla birlikte, bu karşılaştırmayı yaparsanız nesnenin ömrü fonksiyonun tek bir çalışmasına karşılık gelir, böylece dış fonksiyondaki değişkenler kalıcı durumun bir parçasıdır.
Taemyr

@ Taemyr, OP, iç yapının içimdekilere benzeyen bir kamu kurucusu içinde adı verilen özel yöntemleri açıklar. Bir işleve her girdiğinizde üzerine basarsanız, devlet gerçekten 'ısrarcı' değildir. Bazen durum paylaşılan bir yöntem olarak kullanılır, yazabilir ve okuyabilir. Kalması gerektiği anlamına gelmez. Yine de devam etmesi, güvenmesi gereken bir şey değil.
candied_orange

1
Nesneyi her elden çıkardığınızda üzerine bassanız bile kalıcıdır.
Taemyr

1
İyi noktalar, ancak bunları JavaScript'te ifade etmek tartışmayı gerçekten engelliyor. Ayrıca, JS sözdizimini ortadan kaldırırsanız,
sonuçta çevrilen

1
@sdenham Bir sınıfın özellikleri ile bir işlemin geçici ara sonuçları arasında bir fark olduğunu savunuyorum. Eşdeğer değiller. Ancak bir tanesi diğerinde saklanabilir. Kesinlikle olmak zorunda değil. Sorun şu ki olması gerektiğidir. Evet, anlamsal ve yaşam boyu sorunlar var. Ayrıca arite sorunları var. Yeterince önemli olduklarını düşünmüyorsun. Bu iyi. Ancak sınıf seviyesini nesne durumundan başka bir şey için kullanmanın yanlış bir modelleme olduğunu söylemek, bir modelleme yolunda ısrar ediyor. Bunu başka şekilde yapan profesyonel kodları korudum.
Instagram Hesabındaki Resim ve Videoları candied_orange
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.