İşlevleri sadece ortak kodu merkezileştirmek için kullanmak iyi bir uygulama mudur?


20

Bu sorunla çok fazla karşılaşıyorum. Örneğin, şu anda bir okuma işlevi ve yazma işlevi yazıyorum ve her ikisi de bufbir NULL işaretçisi olup olmadığını ve modedeğişkenin belirli sınırlar içinde olup olmadığını kontrol eder .

Bu kod çoğaltmadır. Bu, kendi işlevine taşınarak çözülebilir. Ama yapmalıyım? Bu oldukça anemik bir fonksiyon olacak (fazla bir şey yapmaz), oldukça lokalize (yani genel amaçlı değil) ve kendi başına iyi durmuyor (nerede olduğunu görmedikçe ne için ihtiyacınız olduğunu anlayamıyorsunuz) Kullanılmış). Başka bir seçenek bir makro kullanmaktır, ancak bu yazıdaki işlevler hakkında konuşmak istiyorum.

Peki, böyle bir şey için bir işlev kullanmalı mısınız? Artıları ve eksileri nelerdir?


2
Tek satırlık şeyler, ayrı bir işleve geçmeyi garanti etmek için birden fazla yerde kullanılmasından daha fazlasına ihtiyaç duyar.

1
Harika bir soru. Aynı şeyi merak ettiğim pek çok kez oldu.
rdasxy

Yanıtlar:


31

Bu, işlevlerin büyük bir kullanımıdır.

Bu oldukça anemik bir fonksiyon olacak (fazla bir şey yapmaz) ...

Bu iyi. Fonksiyonlar sadece bir şey yapmalıdır.

oldukça yerelleştirilmiş ...

OO dilinde özel yapın.

(genel amaçlı değil)

Birden fazla vakayı ele alıyorsa , genel amaç budur. Dahası, genelleme işlevlerin tek kullanımı değildir. Onlar gerçekten de (1) aynı kodu bir kereden fazla yazmak için kaydetmek için, aynı zamanda (2) daha okunabilir hale getirmek için kodu daha küçük parçalara bölmek için. Bu durumda hem (1) hem de (2) elde eder. Ancak, işleviniz tek bir yerden çağrılsa bile, yine de (2) ile yardımcı olabilir.

ve kendi başına iyi durmuyor (nerede kullanıldığını görmedikçe ne için ihtiyacınız olduğunu anlayamıyorum).

Bunun için iyi bir isimle gel ve kendi başına iyi duruyor. "ValidateFileParameters" veya başka bir şey. Şimdi kendi başına iyi durumda.


6
Kuyu mal noktaları. Ben (3) tek bir yerde düzeltebilirsiniz zaman tüm kod tabanı çoğaltılmış bir hata için av önlemek önlemek. Kod çoğaltma, oldukça hızlı bir bakım cehennemine yol açabilir.
deadalnix

2
@Deadalnix: İyi nokta. Yazarken, puanlarımın aşırı bir basitleştirme olduğunu fark ettim. Yazma ve Daha kolay hata ayıklama, işleri fonksiyonlara ayırmanın bir yararıdır (ayrı fonksiyonları test etme becerisi gibi).
Kramii Eski Monica'yı

11

Tamamen bir işlev olmalı.

if (isBufferValid(buffer)) {
    // ...
}

Çok daha okunabilir ve daha sürdürülebilir (eğer kontrol mantığı değişirse, sadece tek bir yerde değiştirirsiniz).

Ayrıca, bunlar gibi şeyler kolayca satır içine alınır, böylece işlev çağrısı ek yükleri hakkında endişelenmenize bile gerek kalmaz.

Size daha iyi bir soru sorayım. Bunu nasıl iyi bir uygulama yapmıyor ?

Doğru şeyi yapmak. :)


4
İsBufferValid basitçe, return buffer != null;o zaman orada okunabilirliğe zarar verdiğinizi düşünüyorum.
pdr

5
@pdr: Bu basit durumda, yalnızca bir kontrol ucube zihniniz varsa ve gerçekten, gerçekten, gerçekten tamponun geçerli olup olmadığını kodun nasıl kontrol ettiğini bilmek istiyorsanız okunabilirliği incitir. Yani bu basit durumlarda özneldir.
Spoike

4
@pdr Herhangi bir standart tarafından okunabilirliği nasıl incittiğini bilmiyorum. Diğer geliştiricilerin bir şeyi nasıl yaptığınızı önemsemekten ve ne yaptığınıza odaklanmaktan muafsınız. isBufferValidkesinlikle daha okunabilir (kitabımda) buffer != null, çünkü amacı daha net bir şekilde iletiyor. Ve yine, bahsetmemek bile sizi burada tekrardan kurtarır. Daha ne gerekiyor?
Yam Marcovic

5

IMO, kod parçacıkları , işlevin çok kısa veya sadece bir kez kullanılacağına bakılmaksızın , kodu daha okunabilir hale getirdiğinde kendi işlevlerine taşınmaya değer .

Elbette sağduyunun belirlediği sınırlar vardır. Mesela WriteToConsole(text), vücudun basit olduğu bir yönteme sahip olmak istemezsiniz Console.WriteLine(text). Ancak okunabilirlik tarafındaki hatalar iyi bir uygulamadır.


2

Koddaki çoğaltmayı kaldırmak için işlevleri kullanmak genellikle iyi bir fikirdir.

Ancak çok ileriye götürülebilir. Bu bir yargılama çağrısıdır.

Boş arabellek denetiminizin örneğini almak için, muhtemelen aşağıdaki kodun yeterince açık olduğunu ve aynı desen birkaç yerde kullanılsa bile ayrı bir işleve çıkarılmaması gerektiğini söyleyebilirim.

if (buf==null) throw new BufferException("Null read buffer!");

Hata iletisini genel bir null denetleme işlevine parametre olarak eklerseniz ve işlevi tanımlamak için gereken kodu da göz önünde bulundurursanız, bunun yerine bunu yapmak için net bir LOC tasarrufu olmaz:

checkForNullBuffer(buf, "Null read buffer!");

Ayrıca, hata ayıklama sırasında ne yaptığını görmek için işleve dalmak, işlev çağrısının kullanıcı için daha az "saydam" olduğu anlamına gelir ve bu nedenle daha az okunabilir / bakımı yapılabilir olarak kabul edilebilir.


Muhtemelen, örnekleminiz, dilde sözleşme desteğinin olmaması hakkında gerçek bir çoğaltma ihtiyacından daha fazlasını söylüyor. Ama yine de iyi noktalar.
deadalnix

1
Gördüğüm kadar noktayı kaçırdınız. Değil üzerinden adım veya mantık her zaman hata ayıklama düşünmek zorundayız zorunda budur ben değilim arıyorum. Nasıl yapıldığını bilmek istersem, bir kez kontrol ederim. Her seferinde yapmak zorunda olmak sadece aptalca.
Yam Marcovic

Hata mesajı ("Boş okuma arabelleği") tekrarlanırsa, yineleme işlemi kesinlikle ortadan kaldırılmalıdır.
kevin cline

Bu sadece bir örnektir, ancak muhtemelen her işlev çağrı sitesinde farklı bir mesajınız olacaktır - örneğin "Boş okuma arabelleği" ve "Boş yazma arabelleği". Her durum için aynı günlük / hata mesajlarını istemediğiniz sürece, onu de çoğaltamazsınız .......
mikera

-1 Preconditions.checkNotNull iyi bir uygulama, kötü bir uygulama değil. Dize mesajını eklemenize gerek yok. google-collections.googlecode.com/svn/trunk/javadoc/com/google/…
ripper234

2

Kodun merkezileştirilmesi genellikle her zaman iyi bir fikirdir. Kodu olabildiğince tekrar kullanmalıyız.

Ancak, bunun nasıl yapılacağını not etmek önemlidir . Örneğin, compute_prime_number () veya check_if_packet_is_bad () yapan bir kodunuz varsa, bu iyi olur. Şansı, işlevsellik algoritmasının kendisinden faydalanacak şekilde gelişeceğidir.

Ancak, düzyazı olarak yinelenen herhangi bir kod parçası hemen merkezileşmeye hak kazanmaz. Bu kötü. Sadece bir kodu gizlemek için bir fonksiyonun içindeki rastgele kod satırlarını gizleyebilirsiniz, zamanla, uygulamanın birden çok kısmı kullanılmaya başladığında, hepsi fonksiyonun tüm callee ihtiyaçlarına uyumlu kalmalıdır.

İşte sormadan önce sormanız gereken bazı sorular

  1. Yarattığınız işlevin kendine özgü bir anlamı var mı yoksa sadece bir grup satır mı?

  2. Başka hangi bağlamda aynı işlevlerin kullanılması gerekir? Bunu kullanmadan önce API'yı biraz genelleştirmeniz gerekebilir mi?

  3. İstisnaları attığınızda başvuruların (farklı bölümleri) beklentisi ne olacak?

  4. Fonksiyonların gelişeceğini görmek için senaryolar nelerdir?

Ayrıca böyle bir şey olup olmadığını da kontrol etmelisiniz. O kadar çok insanın zaten var olanı aramak yerine makrolarını MIN, MAX olarak yeniden tanımlama eğiliminde olduğunu gördüm.

Esasen, "Bu yeni işlev gerçekten yeniden kullanılmaya değer mi, yoksa bu sadece bir kopyala yapıştır mı?" Eğer ilkse, gitmek iyidir.


1
Peki, çoğaltılan kodun bir anlamı yoksa, kodunuz size yeniden düzenleme gerektiğini söylüyor. Çünkü çoğaltmanın gerçekleştiği yerlerin muhtemelen kendi anlamları yoktur.
deadalnix

1

Kod çoğaltmasından kaçınılmalıdır. Her tahmin edişinizde kod çoğaltmasından kaçınmalısınız. Bunu tahmin etmediyseniz, aynı kod parçası 3 kez tekrarlanmadan önce 3: refactor kuralını uygulayın, 2 kez tekrarlandığında tuhaflığı canlandırın.

Kod çoğaltma nedir?

  • Kod tabanında birkaç yerde yinelenen bir yordam. Bu tourine, basit bir işlev çağrısından daha karmaşık olmalıdır (aksi takdirde, çarpanlarına ayırarak hiçbir şey kazanamazsınız).
  • Çok yaygın bir görev, hatta önemsiz bir görev (genellikle bir test). Bu kodda kapsülleme ve semantik geliştirir.

Aşağıdaki örneği inceleyin:

if(user.getPrileges().contains("admin")) {
    // Do something
}

olur

if(user.isAdmin()) {
    // Do something
}

Kapsülleme işlemini iyileştirdiniz (şimdi koşulları şeffaf olarak yönetici olarak değiştirebilirsiniz) ve kodun semantiği. Kullanıcının yönetici olup olmadığını kontrol etme biçiminizde bir hata bulunursa, tüm kod tabanınızı atmaya ve her yerde bir düzeltme yapmanıza gerek yoktur (bir tanesini unutma ve uygulamanızda bir güvenlik kusuru alma riskiyle).


1
Btw Örneği Demeter Yasasını göstermektedir.
MaR

1

KURU kod manipülasyonunu basitleştirmekle ilgilidir. Bu ilke hakkında yeni bir noktaya değindiniz: Bu , kodunuzdaki jeton sayısını en aza indirmek değil , anlamsal olarak eşdeğer kod için tek bir değişiklik noktası oluşturmakla ilgilidir . Çeklerinizin her zaman aynı semantiğe sahip olduğu anlaşılıyor, bu yüzden bunları değiştirmeniz gerektiğinde bir işleve dahil edilmelidir.


0

Çoğaltıldığını görürseniz, merkezileştirmenin bir yolunu bulmalısınız.

İşlevler iyi bir yoldur (belki de en iyisi değildir, ancak dile bağlıdır) Söylediğiniz gibi işlev anemik olsa bile, bu şekilde kalacağı anlamına gelmez.

Ya başka bir şey daha kontrol etmeniz gerekiyorsa?

Ekstra kontrol eklemek veya sadece bir işlevi değiştirmek için ihtiyacınız olan tüm yerleri bulacak mısınız?


... diğer yandan, ona asla bir şey eklemeyecek olmanız ihtimali çok yüksekse. Bu durumda da öneriniz hala en iyi yol mu?
EpsilonVector

1
@EpsilonVector benim başparmak kuralı eğer bir kez değiştirmek zorunda kalırsanız o da refactor olabilir. Yani, sizin durumunuzda onu bırakardım ve değiştirmek zorunda kalsaydım, bir işlev haline gelirdi.
Thanos Papathanasiou

0

Aşağıdaki koşulların karşılanması neredeyse her zaman iyidir:

  • okunabilirliği artırır
  • sınırlı kapsamda kullanılır

Daha geniş bir kapsamda, çoğalmaya karşı bağımlılık değişimlerine karşı dikkatli bir şekilde tartmalısınız. Kapsam sınırlama tekniklerine örnekler: özel bölümlerde veya modüllerde halka açılmadan gizleme.

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.