Saf işlevlerin halka açık olmaması için iyi bir neden var mı?


25

Bir iş arkadaşınızla devam eden küçük bir tartışmam vardı. Basitçe söylemek gerekirse, saf olan işlevleri gizlemek / kapsüllemek için iyi bir neden var mı?

"Saf" deyin , wikipedia tanımını kastediyorum :

  • Daima aynı sonuçları aynı girdiden döndürür. (Bu tartışmanın uğruna değer semantiği Foo Create(){ return new Foo(); }yoksa Foo, saf olarak kabul edilir .)
  • Değişken durum (yerel değişkenler hariç) veya G / Ç kullanmaz.
  • Yan etki üretmez.

26
Bir sınıfın böyle bir işlev üyesi yapmamak için yapılan bir argüman olabilir.
Pieter B

6
@PieterB - gerçekten, tüm diller bunu desteklemese de, bazı diller serbest işlevler için bile modülün dahili olmasına izin verir.
Telastyn

3
Senin fikrin neydi? İşlevin saflığının, genel API’de olup olmadığına bağlı olduğunu sanmıyorum.
Andres F.

@andresF. - tartışma aslında sınırsız bir onaylama kuralının kamuya açıklanması gerekip gerekmediğiyle ilgilidir. Tartışmayı saf bir işlev olduğu için çok az zarar olduğu iddiasında bulundum. Bu özel örnek için, test edilebilirliğe yardımcı oldu ve tekrar kullanılması muhtemeldi. Bu soru, bu argümanın ne kadar geniş kapsamlı olarak uygulanabileceği / uygulanabileceği ile ilgilidir.
Telastyn 26:14

2
@Telastyn Yeniden kullanılabilir durumdaysa ancak mevcut sınıfın sorumluluğunun bir parçası değilse, muhtemelen ayrı bir sınıf / modül / diliniz ne olursa olsun olmalıdır. O zaman yeni sınıf / modülün sorumluluğunun bir parçası olarak, mutlaka kamuya açıklanacaktı. Testten bahsettiğinizden beri, bunu yaparken yöntemi mutlaka alay etmeniz gerekmediğini unutmayın. Bir "uygulama detayı" olarak testler sırasında alay etmek çok az fayda sağlar.
jpmc26

Yanıtlar:


76

Saf bir fonksiyon hala bir uygulama detayı olabilir. Her ne kadar işlev zarar vermese de (önemli değişmezleri / sözleşmeleri kırmama bakış açısıyla), hem yazarı hem de sınıf / modül / paketin kullanıcılarını ifşa ederek kaybeder. Yazar kaybeder, çünkü uygulama değişse ve işlev artık onun için kullanışlı olmasa bile, kaldıramaz. Kullanıcılar kaybederler, çünkü bunu anlamak için API'yi kullanmakla ilgili olmayan ek işlevleri gözden geçirmek ve yok saymak zorunda kalırlar.


33
+1. Sınıfınızın genel üyeleri API'sıdır. Bu, "Halka açıksa bana zarar verebilir mi?" Değil, "API'nin bir parçası mı olmalı?" Sorusu değil.
Ordous

1
Ekleyeceğim tek şey, başka yerlerde ortaya çıkan benzer işlevleri görmeye başlarsanız, başka bir sınıfa yeniden yansıtmak, böylece çoklu sınıfların faydalanabilmesidir. Ya da başlamak için bir endişe ise, başlamak için ayrı bir sınıfta tanımlayın.
jpmc26

1
Uzatılması amaçlanmayan kamu sınıflarını da mühürlerdim.
Den

Bir işlevi (veya sınıfı) gizleme veya göstermenin öncelikli olarak bir API'yi koruma ve sürdürme sorusudur ve olduğu kod türüyle ilgili değildir.
Marco

42

Soru geriye doğru.

Halka açık olmayan bir işlevi yapmak için bir sebep aramazsınız. Başlamak için yanlış bir zihniyet var (bence). Akıl yürütme diğer tarafa gitmeli.

Başka bir deyişle - "neden özel yapacağım?" Diye sorma. "Neden herkese açık hale getireyim?" Diye sor.

Şüphe duyduğunuzda, açığa vurmayın. Ockham'ın jilet gibi bir şey - gerekli olanın ötesinde hakları çoğaltmayın.

DÜZENLEME: @Telastyn tarafından yorumlarda ortaya konan karşı davalara hitap etmek (burada genişletilmiş tartışmaları önlemek için):

Bunu zamanla duydum ve hatta uzunca bir süredir teşvik ettim, ama deneyimlerime göre işler çok özel olma eğilimindeydi.

Evet, bazen bir sınıf mirasa açıksa bu bir acıdır, ancak bazı özel yöntemleri (davranışını değiştirmek istediğiniz) geçersiz kılamazsınız.

Ama protectedyeterli olurdu - ve hala halka açık değil.

Her ne kadar dolaylı olarak erişildiyse de, “kamuya açık olmaması gereken şeylere” ulaşmak birçok kod çoğaltmasına ve ek yüke yol açar.

Sorunlu olursa, o zaman herkese açık yapın! Bahsettiğim zorunluluk var :)

Demek istediğim bunu yapamaz gerektiğidir ihtimale (YAGNI ve tüm).

Özel bir işlevi herkese açık kılmak, onu gizliliğe geri çekmek yerine her zaman daha kolay olduğunu unutmayın. İkincisi mevcut kodu kırma olasılığı yüksektir.


Bunu zamanla duydum ve hatta uzunca bir süredir teşvik ettim, ama deneyimlerime göre işler çok özel olma eğilimindeydi. Her ne kadar dolaylı olarak erişildiyse de, “kamuya açık olmaması gereken şeylere” ulaşmak birçok kod çoğaltmasına ve ek yüke yol açar.
Telastyn 26:14

3
@Telastyn IMHO, uygulama gibi sesler bazı tasarım yanlışlıklarından muzdarip; Kendinizi bir yöntemi ifşa etmeye meyilli bulursanız, bunu ayrı kod yollarına çağırmanız gerektiğine işaret ediyorsanız, bu yöntemin enjekte edilebilecek veya uygun olan durumlarda, özellikle saf bir işlevse dahil edilebilecek kendi modülüne ayrılması gerektiğinin bir işareti olabilir. .
leo

@leo - üzgünüm takip etmiyorum. Tamsayı gibi bir işlevi daha az düşünün. Bu, özellikle maruz kaldığı için hoş bir saf fonksiyondur, çünkü uygun olduğunda enjekte edilebilir ve dahil edilebilir (veya basitçe kullanılabilir).
Telastyn

5
@Telastyn Kanımca, bazı OOP dillerinin sınıflardan başka kompozit veri türlerinin olmaması gerçeğiyle bir araya gelen "her şey bir nesne / sınıf" felsefesinin bir belirtisi olduğunu düşünüyorum. Biri aynı anda iki değeri geçmek zorunda kaldıklarında bir sınıf yazıyorlar ve ardından her iş arkadaşı ve stil kontrol yazılımı size bu alanları özel hale getirmenizi söyleyecek.
Doval

@Telastyn Sağ. Demek istediğim, 'integerLessThan' yönteminiz, halka açık bir yöntemin kapsüllenmiş bir uygulama detayı olarak başladıysa, ancak başka yerlerde özel yöntemi çağırmanız gerektiğini fark ederseniz, bu muhtemelen özel yöntemin farklı bir alana ait olduğunun bir işaretidir. modül / paket / sınıf böylece onu çağıran mantıktan bağımsız olarak içe aktarılabilir. Yöntemi olduğu gibi basit bir şekilde yayınlamak, yöntemin keyfi olarak bulduğunuz ilk modülde bulunduğu anlamına gelir.
leo

6

Bir işlevi gizleme / kapsama kararının saflığına bağlı olduğunu düşünmüyorum. Sadece bir fonksiyonun saf olması, dışsalların bunu bilmesi gerektiği anlamına gelmez. İşlev, eğer safsa ve halka açıksa, belki de arayüzün bir üyesi olması gerekmediği halde, belki de statik olarak daha uygun olsa da, yeterince ilginçtir. Fakat yine de, tüm bunlar sözleşmenin amacına ve bu durumda, işlevin saflığına değil, işlevselliğin mantıksal gruplamasına bağlıdır.


5

Sınıflar, Tek Sorumluluk İlkesine bağlı kalmalıdır . Bir sınıf, hedeflerine ulaşmak için diğer işlevleri çağırması gerekebilirken, yalnızca kendi sorumluluğunun bir parçası olan işlevleri ortaya çıkarmalıdır.

Görünürlük bir soruna neden olabilir bir durumda sadece bir örnek .

Aletleri frobnicate eden bir sınıf düşünün. Belki frobnication kodunun bir parçası olarak, bir dizgeyi ayrıştırmak için bazı yardımcı işlevlere ihtiyaç duyar: belki de dize isminin standart dize işlevlerinin desteklemeyeceği şekilde dönüştürülmesi gerekir.

Bu saf bir fonksiyon olduğu için (string gelir, bir şekilde dönüştür, yeni string döndür), sonuçsuz kamuya açık ya da özel olabilir. Veya olabilir mi?

Kamuya açıklarsan, şimdi sınıfının iki sorumluluğu var: frobnicing widget'ları ve karakter dizileri. Bu, SRP'yi ihlal eder ve başka sınıflar işleve güvenirse sorunlara neden olabilir. Bu, sadece sınıfa dahil olduğunu düşündüğünüz bir şey olduğundan, belki onun arayüzünü veya görünürlüğünü değiştirirsiniz. Şimdi sistemin diğer bölümlerindeki sınıflar bozuldu.

Bu fonksiyonu özel kılmakla, hiç kimse sınıfın tek sorumluluğunun bir parçası olmayan koda güvenme olanağına sahip olmadı.


2
Sadece ifşa etme değil, sadece kendi sorumluluğunun bir parçası olan fonksiyonları içermesi gerektiğini savunuyorum .
Telastyn 26:14

1
Bence gri bir alan var. StringTransformerSadece bir yerde kullanılan iki veya üç kod satırını içine almak için gerçekten ayrı bir sınıfa mı ihtiyacınız var ? Birden fazla yerde kod kullanıldığında, tek bir sorumlulukla onu yeni bir sınıfa ayırmanın en iyisi olduğuna katılıyorum, ancak bir değişim yaşanıyor.

Kesinlikle. Kurallar kuraldır, kural değildir.
Telastyn

Java olmayan bir yerde snowman, sadece bir fonksiyon kütüphanesi hazırlarsınız.
Pieter B

@ PieterB, Java ile ilgili değildir. Başka bir şey yoktur. Gerçekten
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.