'Util' dersleri almak endişe yaratıyor mu? [kapalı]


14

Bazen esasen başka bir yere ait gibi görünmeyen yöntemleri ve değerleri tutmaya yarayan 'Util' sınıfları yaratırım. Ama bu sınıflardan birini her oluşturuşumda, sanırım "uh-oh, bundan sonra pişman olacağım ...", çünkü kötü bir yerde okudum.

Ancak öte yandan, onlar için iki zorlayıcı (en azından benim için) vakalar var gibi görünüyor:

  1. paket içindeki birden fazla sınıfta kullanılan uygulama sırları
  2. arabirimini karmaşıklaştırmadan bir sınıfı artırmak için kullanışlı işlevsellik sağlamak

Yıkım yolunda mıyım? Ne diyosun !! Refactor yapmalı mıyım?


11
UtilSınıflarınızın adlarında kullanmayı bırakın . Sorun çözüldü.
yannis

3
@MattFenwick Yannis iyi bir noktaya sahiptir. Bir sınıfı adlandırmak SomethingUtilbiraz tembeldir ve sadece sınıfın gerçek amacını gizler - SomethingManagerveya adlı sınıflarla aynı SomethingService. Eğer bu sınıfın tek bir sorumluluğu varsa, ona anlamlı bir isim vermek kolay olmalıdır. Değilse, bu başa çıkmak için gerçek sorun ...
MattDavey

1
@MDavey iyi bir nokta, muhtemelen kullanmak için kötü bir kelime seçim oldu Util, ancak açıkçası ben bunu sabit olacağını beklemiyorduk ve sorunun geri kalanı yok sayıldı ...

1
Hangi tür nesnelerle işlediklerini ayırarak birden fazla * Util sınıfı oluşturursanız, bunun iyi olduğunu düşünüyorum. Bir StringUtil, ListUtil, vb sahip herhangi bir sorun görmüyorum. C # değilseniz sürece o zaman genişletme yöntemleri kullanmalısınız.
marco-fiset

4
Sıklıkla ilgili amaçlar için kullanılan işlevlerim vardır. Gerçekten bir sınıfa iyi eşlemiyorlar. ImageResizer sınıfına ihtiyacım yok, sadece ResizeImage fonksiyonuna ihtiyacım var. Böylece ilgili işlevleri ImageTools gibi statik bir sınıfa koyacağım. Henüz herhangi bir gruplandırmada yer almayan fonksiyonlar için, onları tutacak bir Util statik sınıfım var, ancak bir sınıfa sığacak kadar birbiriyle ilişkili birkaç tane var, onları taşıyacağım. Bunu halletmek için daha iyi bir OO yolu göremiyorum.
Philip

Yanıtlar:


26

Modern OO tasarımı, her şeyin bir nesne olmadığını kabul eder . Bazı şeyler davranış veya formüldür ve bazılarının durumu yoktur. Bu tasarımdan yararlanmak için bunları saf işlevler olarak modellemek iyidir.

Java ve C # (ve diğerleri) bir util sınıfı oluşturmanızı ve bunu yapmak için bu kasnağa atlamanızı gerektirir. Can sıkıcı, ama dünyanın sonu değil; ve tasarım açısından gerçekten zahmetli değil.


Evet, böyle düşünüyordum. Yanıtınız için teşekkürler!

Kabul edilmesine rağmen, .NET'in şimdi bu yaklaşıma alternatif olarak genişletme yöntemleri ve kısmi sınıflar sunduğu belirtilmelidir. Bu öğeyi aşırıya çıkarırsanız, yardımcı sınıflara çok az ihtiyacı olan bir dil olan Ruby mixins ile sonuçlanırsınız.
neontapir

2
@neontapir - Genişletme yöntemlerinin uygulanması dışında temelde genişletme yöntemleriyle bir util sınıfı yapmaya zorlar ...
Telastyn

Doğru. Util sınıflarının engellediği iki yer vardır, biri sınıfın kendisinde diğeri çağrı sitesidir. Yöntemler, geliştirilmiş nesne üzerinde varmış gibi görünerek, uzantı yöntemleri çağrı sitesi sorununu giderir. Katılıyorum, hala Util sınıfının varlığı sorunu var.
neontapir

16

Asla asla Deme"

Mutlaka kötü olduğunu düşünmüyorum, sadece kötü yapar ve kötüye kullanırsanız kötüdür.

Hepimiz Araçlara ve Yardımcı Programlara İhtiyacımız Var

Yeni başlayanlar için hepimiz bazen neredeyse her yerde ve mutlaka sahip olunması gereken bazı kütüphaneler kullanıyoruz. Örneğin, Java dünyasında, Google Guava'da veya bazı Apache Commons'ta ( Apache Commons Lang , Apache Commons Koleksiyonları , vb.).

Yani bunlara açıkça ihtiyaç var.

Zor Kelime, Çoğaltma ve Tanıtıcı Hatalardan Kaçının

Bu konuda düşünüyorsanız hemen hemen bunlardan sadece çok büyük bir demet Utilbirisi onları (nispeten) hakkını almak için büyük çaba geçti dışında açıkladığınız sınıflar ve onlar been zaman - test ve ağır başkaları tarafından göz balled.

Bu yüzden, bir Utilsınıf yazmak için kaşıntı hissederken ilk kuralın, Utilsınıfın gerçekten var olmadığını kontrol etmek olduğunu söyleyebilirim .

Bunun için gördüğüm tek karşı-argüman bağımlılıklarınızı sınırlamak istediğiniz zamandır çünkü:

  • bağımlılıklarınızın bellek ayak izini sınırlamak istiyorsunuz,
  • veya geliştiricilerin kullanmasına izin verilenleri sıkı bir şekilde kontrol etmek istersiniz (obsesif büyük ekiplerde veya belirli bir çerçeve, kesinlikle bir yerde kaçınmak için garip süper berbat sınıfın olmasıyla bilinir).

Ancak bunların her ikisi de, ProGuard veya eşdeğeri kullanılarak lib'in yeniden paketlenmesi veya kendinizin parçalanmasıyla ele alınabilir ( Maven kullanıcıları için, maven-gölge eklentisi bunu yapınızın bir parçası olarak entegre etmek için bazı filtreleme desenleri sunar ).

Dolayısıyla, bir lib'taysa ve kullanım durumunuzla eşleşiyorsa ve hiçbir kıyaslama size bunun aksini söylemiyorsa kullanın. Sizden biraz farklıysa, uzatın (mümkünse) veya uzatın veya son çare olarak yeniden yazın.

Adlandırma Kuralları

Ancak şimdiye kadar bu cevapta onlara Utilsenin gibi dedim . Onlara böyle isim verme.

Onlara anlamlı isimler verin. Google Guava'yı ne yapacağınıza dair (çok, çok) iyi bir örnek olarak alın ve com.google.guavaad alanının aslında sizin kökünüz olduğunu hayal edin util.

utilEn kötü ihtimalle paketinizi arayın , ama sınıfları değil. StringNesneler ve dize yapılarının manipülasyonu ile ilgileniyorsa , onu arayın Strings, değil StringUtils(üzgünüm, Apache Commons Lang - Seni hala seviyorum ve kullanıyorum!). Belirli bir şey yaparsa, belirli bir sınıf adı seçin ( Splitterveya gibi Joiner).

Ünite testi

Bu yardımcı programları yazmak için başvurmanız gerekiyorsa, bunları birim olarak test ettiğinizden emin olun. Yardımcı programlarla ilgili iyi olan şey, genellikle belirli girdileri alan ve belirli çıktıları döndüren bağımsız bileşenlerdir. Kavram budur. Bu yüzden onları birim test etmemek için bir mazeret yoktur.

Ayrıca, birim testi, API'larının sözleşmesini tanımlamanıza ve belgelemenize olanak tanır. Testler bozulursa, bir şeyi yanlış bir şekilde değiştirdiniz veya API'nızın sözleşmesini değiştirmeye çalıştığınız (veya orijinal testlerinizin boktan olduğunu öğrenin - tekrar öğrenin ve bir daha yapmayın) .

API Tasarımı

Bu API'lar için alacağınız tasarım kararı muhtemelen sizi uzun süre takip edecektir. Bu nedenle, Splitter-klon yazmak için saat harcamakla birlikte , soruna nasıl yaklaştığınıza dikkat edin.

Kendinize birkaç soru sorun:

  • Fayda yönteminiz bir sınıfı tek başına garanti ediyor mu veya benzer bir yöntem grubunun parçası olması mantıklıysa statik bir yöntem yeterince iyi mi?
  • Nesneleri oluşturmak ve API'larınızı daha okunabilir hale getirmek için fabrika yöntemlerine mi ihtiyacınız var ?
  • Okunabilirlikten bahsetmişken, bir Akıcı API'ye , oluşturuculara vb. İhtiyacınız var mı?

Bu araçların geniş bir kullanım senaryolarını kapsamasını, sağlam, istikrarlı, iyi belgelenmiş olmasını, en az sürpriz ilkesini takip etmesini ve bağımsız olmasını istersiniz. İdeal olarak, aletlerinizin her bir alt paketi ya da en azından bütün paketiniz kolay yeniden kullanım için bir pakete ihraç edilebilir.

Her zamanki gibi, burada devlerden öğrenin:

Evet, bunların birçoğu koleksiyonlara ve veri yapılarına vurgu yapıyor, ancak bana, doğrudan veya dolaylı olarak araçlarınızın çoğunu nerede ya da ne için uygulayacağınızı söylemeyin.


+1 içinIf deals with String objects and manipulation of string constructs, call it Strings, not StringUtils
Tulains Córdova


Neden StringUtil (ler) yerine Dizeler olarak adlandırıyorsunuz? Bana ipler bir koleksiyon nesnesi gibi geliyor.
bdrx

@bdrx: Bana StringsCollectionTypeHeresomut bir uygulama istiyorsanız bir koleksiyon nesnesi olurdu . Veya bu dizelerin uygulamanız bağlamında belirli bir anlamı varsa daha belirgin bir ad. Bu özel durum Stringsiçin Guava, StringUtilsCommons Lang'da olduğu gibi iplerle ilgili yardımcıları için kullanıyor . Mükemmel kabul edilebilir buluyorum, bu sadece benim için sınıfların Stringnesneyi ele aldığı veya Dizeleri yönetmek için genel amaçlı bir sınıf olduğu anlamına gelir .
haylem

@bdrx: Genel olarak NameUtilsbeni açıkça etiketlenmiş bir paket adı altında oturur, bir yardımcı sınıf (ve eğer değilse, hızlı bir şekilde API bakarak anlamaya olurdu) biliyorum çünkü sonu beni rahatsız . İnsanların olarak malzeme bildirerek olarak benim için can sıkıcı olarak var SomethingInterface, ISomethingya SomethingImpl. Ben IDEs kullanarak C kodlama ve böyle eserler ile Tamam tür oldu. Bugün genellikle böyle şeylere ihtiyacım olmayacaktı.
haylem

8

Util sınıfları birbirine bağlı değildir ve genellikle kötü tasarımlıdır çünkü bir sınıfın değiştirmek için tek bir nedeni olmalıdır (Tek Sorumluluk İlkesi).

Oysa ben gibi çok Java API sınıfları, "util" gördüm: Math, Collectionsve Arrays.

Bunlar aslında yarar sınıflarıdır, ancak tüm yöntemleri tek bir tema ile ilgilidir, birinin matematiksel işlemleri vardır, biri koleksiyonları manipüle etmek için diğeri de dizileri manipüle etmek için yöntemleri vardır.

Bir yardımcı program sınıfında tamamen ilgisiz yöntemlere sahip değilsiniz. Eğer durum buysa, onları gerçekten ait oldukları yere koyabilirsiniz.

Sınıflar util olması gerekiyorsa o zaman onları tema ile ayrılmalıdır deneyin Java'nın gibi Math, Collectionsve Arrays. En azından, sadece isim alanları olsa bile tasarımın bir niyeti olduğunu gösteriyor.

Birincisi, her zaman yardımcı sınıflardan kaçının ve asla bir tane yaratma ihtiyacı duymadım .


Yanıtınız için teşekkürler. Peki, util sınıfları paket özel olsa bile, hala bir tasarım kokusu mu?

her şey bir sınıfa ait değil. eğer bu dilin ısrar ettiği bir dille sıkışırsanız, o zaman sınıfları kullanır.
jk.

1
Fayda sınıfları, kaç yöntemin çok fazla olduğunu size bildiren bir tasarım prensibine sahip değildir, çünkü başlangıçta uyumluluk yoktur. Nasıl duracağınızı nasıl bilebilirsiniz? 30 yöntemden sonra? 40? 100 ? OOP prensipleri ise, bir yöntemin belirli bir sınıfa ait olmadığı ve sınıfın ne kadar çok şey yaptığı konusunda size bir fikir verir. Buna bağlılık denir. Ama cevabımda söylediğim gibi, Java'yı tasarlayan insanlar yardımcı program sınıfları kullandılar. Sen de yapamazsın. Fayda sınıfları oluşturmuyorum ve normal bir sınıfa ait olmayan bir durumda olmadım.
Tulains Córdova

1
Utils sınıfları genellikle sınıflar değildir , sadece bir grup, genellikle saf fonksiyon içeren ad alanlarıdır. Saf fonksiyonlar alabildiğiniz kadar yapışkandır.
jk.

1
@jk Utils demek istedim ... Bu arada tasarım gibi bir isimle ortaya çıkıyor Mathya Arraysda en azından bir niyeti gösteriyor.
Tulains Córdova

3

Bu terimi tercih etsem de, util sınıflarına sahip olmak tamamen kabul edilebilir ClassNameHelper. .NET BCL'nin içinde yardımcı sınıflar bile var. Hatırlanması gereken en önemli şey, her bir yardımcı yöntemin yanı sıra sınıfların amacını ayrıntılı olarak belgelemek ve onu yüksek kaliteli sürdürülebilir kod yapmaktır.

Ve yardımcı sınıflarla taşınmayın.


0

İki katmanlı bir yaklaşım kullanıyorum. "Util" paketindeki (klasör) bir "Globals" sınıfı. Bir şeyin "Globals" sınıfına veya "util" paketine girmesi için şu şekilde olması gerekir:

  1. Basit,
  2. değişmeyen,
  3. Başvurunuzdaki başka hiçbir şeye bağımlı değil

Bu testleri geçen örnekler:

  • Sistem çapında tarih ve ondalık biçimler
  • EARLIEST_YEAR (sistemin desteklediği) veya IS_TEST_MODE veya bazı gerçek ve küresel (değişmez) (sistem çalışırken) gibi değişmez global veriler.
  • Diliniz, çerçeveniz veya araç setinizdeki boşluklar üzerinde çalışan çok küçük yardımcı yöntemler

Aşağıda, uygulamanın geri kalanından tamamen bağımsız çok küçük bir yardımcı yöntem örneği verilmiştir:

public static String ordinal(final int i) {
    return (i == 1) ? "1st" :
           (i == 2) ? "2nd" :
           (i == 3) ? "3rd" :
           new StringBuilder().append(i).append("th").toString();
}

Buna baktığımda 21 "21", 22 "22", vb. Olması gereken bir hatayı görebiliyorum ama bu konunun yanında.

Bu yardımcı yöntemlerden biri büyür veya karmaşık hale gelirse, util paketinde kendi sınıfına taşınmalıdır. Util paketindeki iki veya daha fazla yardımcı sınıf birbiriyle ilişkiliyse, kendi paketlerine taşınmalıdır. Bir sabit veya yardımcı yöntem uygulamanızın belirli bir bölümüyle ilişkili olduğu ortaya çıkarsa, oraya taşınmalıdır.

Bir Globals sınıfına veya util paketine yapıştığınız her şey için neden daha iyi bir yer olmadığını doğrulayabilmelisiniz ve yukarıdaki testleri kullanarak periyodik olarak temizlemelisiniz. Aksi takdirde, sadece bir karmaşa yaratıyorsunuz.

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.