Dizelerle eşleştirme, sınıf yöntemlerinden daha mı gevşek?


18

Swing kullanarak Java'da bir okul grubu projesine başlıyorum. Veritabanı masaüstü uygulamasında basit bir GUI.

Profesör bize geçen yılki projenin kodunu verdi, böylece işleri nasıl yaptığını görebildik. Benim ilk izlenim kod olması gereken çok daha karmaşık olmasıdır, ama programcılar sadece yazmadım koda bakarken sık sık bunu düşünüyorum.

Sisteminin iyi veya kötü olmasının nedenlerini bulmayı umuyorum. (Profesöre sordum ve daha sonra neden daha iyi olduğunu göreceğimi söyledi, bu da beni tatmin etmiyor.)

Temel olarak, onun devam eden nesneleri, modelleri (iş mantığı) ve görünümleri arasında herhangi bir birleşmeyi önlemek için, her şey dizelerle yapılır. Veritabanında saklanan persistable nesneler dizelerin karma vardır ve modeller ve görünümler birbirlerine abone olurlar, abone oldukları "olaylar" için dize anahtarları sağlarlar.

Bir etkinlik tetiklendiğinde, görünüm veya model, o etkinlik için ne yapılacağına karar veren tüm abonelerine bir dize gönderir. Örneğin, görünümler eylem dinleyici yöntemlerinden birinde (bunun sadece bicycleMakeField öğesini persistable nesneye ayarladığına inanıyorum):

    else if(evt.getSource() == bicycleMakeField)
    {
        myRegistry.updateSubscribers("BicycleMake", bicycleMakeField.getText());
    }

Bu çağrı en sonunda Araç modelinde bu yönteme ulaşır:

public void stateChangeRequest(String key, Object value) {

            ... bunch of else ifs ...

    else
    if (key.equals("BicycleMake") == true)
    {
                ... do stuff ...

Profesör, bu tür şeyler yapmanın, görüşün bir iş mantığı nesnesine bir yöntem çağırmasından daha genişletilebilir ve sürdürülebilir olduğunu söylüyor. Görüşler ve modeller arasında bir eşleşme olmadığını, çünkü birbirlerinin varlığını bilmediklerini söylüyor.

Bence bu daha kötü bir eşleştirme türüdür, çünkü görünüm ve model çalışmak için aynı dizeleri kullanmak zorundadır. Bir görünümü veya modeli kaldırır veya bir dizede yazım hatası yaparsanız, derleme hatası almazsınız. Ayrıca kod olması gerektiğini düşündüğümden çok daha uzun yapar.

Bunu onunla tartışmak istiyorum, ancak deneyimsiz öğrenci olarak benim yapabileceğim herhangi bir tartışmaya karşı koymak için endüstri deneyimini kullanıyor. Benim yaklaşımımın kaçırdığım bir avantajı var mı?


Açıklığa kavuşturmak için, yukarıdaki yaklaşımı, görüşün modele açıkça bağlı olmasıyla karşılaştırmak istiyorum. Örneğin, araç modeli nesnesini görünüme aktarabilir ve ardından aracın "markasını" değiştirmek için şunları yapabilirsiniz:

vehicle.make = bicycleMakeField.getText();

Bu, SADECE aracın markasını tek bir yerde okunabilir tek bir kod satırına ayarlamak için şu anda kullanılan 15 kod satırını azaltacaktır. (Ve bu tür bir işlem uygulama boyunca yüzlerce kez yapıldığından, okunabilirlik ve güvenlik için büyük bir kazanç olacağını düşünüyorum.)


Güncelleme

Takım liderim ve ben, çerçeveyi statik yazarak nasıl yapmak istediğimizi yeniden yapılandırdık, profesörü bilgilendirdik ve bir demo verdik. Ondan yardım istemediğimiz sürece ve ekibimizin geri kalanını hızlandırabiliyorsak, bu bizim için adil görünüyor, çerçevemizi kullanmamıza izin verecek kadar cömert.


12
OT. Bence profesörünüz kendini güncellemeli ve eski kodu kullanmamalıdır. Akademide 2006'dan beri JAVA sürümünü kullanmak için hiçbir neden yoktur.
Farmor

3
Sonunda cevabını aldığınızda lütfen bizi haberdar edin.
JeffO

4
Kodun kalitesinden veya tekniğin bilgeliğinden bağımsız olarak, tanımlayıcı olarak kullanılan dizelerin açıklamasından "sihirli" kelimesini bırakmalısınız. "Sihirli teller", sistemin mantıklı olmadığını ima eder ve görüşünüzü renklendirir ve eğitmeninizle yaptığınız her tartışmayı zehirler. "Anahtarlar", "adlar" veya "tanımlayıcılar" gibi kelimeler daha tarafsız, belki daha açıklayıcıdır ve yararlı bir sohbetle sonuçlanma olasılığı daha yüksektir.
Caleb

1
Doğru. Onunla konuşurken onlara sihirli teller demedim, ama haklısın, sesi daha kötü hale getirmeye gerek yok.
Philip

2
Profesörünüzün açıkladığı yaklaşım (dize adı verilen olaylar aracılığıyla dinleyicileri bilgilendirmek) iyi olabilir. Aslında numaralandırmalar daha anlamlı olabilir, ancak bu en büyük sorun değildir. Burada gördüğüm asıl sorun, bildirimi alan nesnenin modelin kendisidir ve sonra olayın türüne göre manuel olarak gönderilmesi gerektiğidir. İşlevlerin birinci sınıf olduğu bir dilde , bir olaya nesne değil, bir işlevi kaydedersiniz . Java, sanırım biri tek bir işlevi sarma bir tür nesne kullanmak gerekir
Andrea

Yanıtlar:


32

Profesörünüzün önerdiği yaklaşım en iyi şekilde dize olarak yazılmıştır ve hemen hemen her düzeyde yanlıştır.

Kuplaj, en iyi şekilde, bir dizi vakayı kablolamak yerine, polimorfik bir sevk ile yapan bağımlılık tersine çevirme ile azaltılır .


3
"Hemen hemen her seviyede" yazıyorsunuz, ancak bu örnekte neden uygun bir vaka (sizce) yazmadınız. Bilmek ilginç olurdu.
hakre

1
@hakre: Uygun bir durum yok, en azından Java'da değil. Dedim ki, "hemen hemen her seviyede yanlış", çünkü hiçbir dolaylama kullanmamaktan ve tüm kodu tek bir yere atmaktan daha iyidir. Bununla birlikte, (global) sihirli dize sabitlerini manuel bir gönderim için temel olarak kullanmak, sonunda global nesneleri kullanmanın karmaşık bir yoludur.
back2dos

Yani argümanınız: Asla uygun durumlar yok, yani bu da değil mi? Bu pek tartışılmaz ve aslında çok da yardımcı değil.
hakre

1
@hakre: Benim iddiam, bu yaklaşımın birkaç nedenden ötürü kötü olduğudur (paragraf 1 - bundan kaçınmak için yeterli nedenler, dizilmiş tipin açıklamasında verilmiştir) ve kullanılmamalıdır, çünkü daha iyi bir yaklaşım vardır (paragraf 2) ).
back2dos

3
@hakre Bir seri katilin sizi koltuğunuza kanalize ettiyse ve kafanızda bir motorlu testere tutuyor, manik olarak gülüyor ve sevk mantığı için her yerde dize değişmezleri kullanmasını emrediyorsa, bu yaklaşımı garanti edecek bir durum hayal edebiliyorum. Kısacası, bu tür şeyleri yapmak için dil özelliklerine güvenmek tercih edilir. Aslında, timsah ve ninjaları içeren başka bir vakayı düşünebilirim, ama bu biraz daha ilgili.
Rob

19

Profesörünüz yanlış yapıyor . O çalışıyor tamamen içinde dizesi yoluyla seyahat etmek iletişimi zorlayarak Decouple görünümü ve modeline (görünüm modeli ve modele bağlı değildir görünüme bağlı değildir) her iki yönde tamamen nesne yönelimli tasarım ve MVC amacı yendi, hangi. Sınıf yazmak ve OO tabanlı bir mimari tasarlamak yerine, metin tabanlı mesajlara cevap veren farklı modüller yazıyor gibi görünüyor .

Profesör için biraz adil olmak gerekirse, Java'da INotifyPropertyChanged, hangi özelliklerin değiştiğini belirten dizeleri geçirerek değişiklik olaylarını abonelere bildiren oldukça yaygın .NET arayüzüne çok benzeyen bir şey yaratmaya çalışıyor . En azından .NET'te, bu arabirim öncelikle nesneleri ve GUI öğelerini (bağlama) görüntülemek için bir veri modelinden iletişim kurmak için kullanılır.

Doğru yapılması halinde , bu yaklaşımla olabilir bazı benefits¹ var:

  1. Görünüm, Modele bağlıdır, ancak Modelin Görünüme bağlı olması gerekmez. Bu uygun bir Kontrol Tersine Çevirme'dir .
  2. Görünüm kodunuzda, modelden gelen değişiklik bildirimlerine yanıt vermeyi yöneten tek bir yeriniz ve abone olmak / abonelikten çıkmanız için yalnızca bir yeriniz var;
  3. Etkinlik yayıncısına bir etkinlik eklemek veya kaldırmak istediğinizde daha az kodlama yükü vardır. .NET'te, yerleşik bir yayınlama / abone olma mekanizması vardır, eventsancak Java'da sınıflar veya nesneler oluşturmanız ve her olay için abone olma / abonelikten çıkma kodu yazmanız gerekir.
  4. Bu yaklaşımdaki en büyük düşüş, abone kodunun yayın koduyla senkronize olmayabileceğidir. Ancak, bu bazı geliştirme ortamlarında da bir avantajdır. Modelde yeni bir etkinlik geliştirilirse ve görünüm henüz ona abone olacak şekilde güncellenmezse, görünüm yine de çalışır. Benzer şekilde, bir etkinlik kaldırılırsa, bazı ölü kodlarınız vardır, ancak yine de derlenebilir ve çalıştırılabilir.
  5. En azından .NET'te, Yansıma, aboneye iletilen dizeye bağlı olarak alıcıları ve ayarlayıcıları otomatik olarak çağırmak için çok etkili bir şekilde kullanılır.

Kısacası (ve sorunuzu cevaplamak için) yapılabilir, ancak profesörünüzün kullandığı yaklaşım, Görünüm ve Model arasında en az tek yönlü bir bağımlılığa izin vermemek için hatalıdır. Bu pratik değil, aşırı akademik ve eldeki araçların nasıl kullanılacağına dair iyi bir örnek değil.


People Uygulama sırasında sihirli dizgi kullanmaktan kaçınmaya çalışanINotifyPropertyChanged milyonlarca yol bulmak için Google'da arama yapın .


Burada SABUN'u tarif ettiğiniz gibi görünüyor. : D… (ama evet, ne demek istediğimi anladın ve haklısın)
Konrad Rudolph

11

enumpublic static final StringSihirli Dizeler yerine s (veya s) kullanılmalıdır.

Profesörünüz OO'yu anlamıyor . Örneğin somut bir Araç sınıfına sahip olmak?
Ve bu sınıfın bisiklet yapımını anlamasını sağlamak için?

Araç soyut olmalı ve Bike adında somut bir alt sınıf olmalıdır. İyi bir not almak ve daha sonra öğretisini unutmak için kurallarına göre oynardım.


3
Bu uygulamanın amacı daha iyi OO ilkeleri kullanarak kodu geliştirmek olmadığı sürece. Bu durumda, uzaklara bak.
joshin4colours

2
@ joshin4colours Eğer StackExchange derecelendiriyor olsaydınız, doğru olurdu; ancak sınıf öğrencisi aynı fikirde olduğu için hepimize kötü notlar vereceğinden, uygulamasının daha iyi olduğunu bilir.
Dan Neely

7

İyi bir noktanız olduğunu düşünüyorum, sihirli teller kötü. Ekibimdeki biri birkaç hafta önce sihirli dizelerden kaynaklanan bir sorunu ayıklamak zorunda kaldı (ama kendi kodlarında yazdım, bu yüzden ağzımı kapalı tuttum). Ve bu oldu ... endüstride !!

Yaklaşımının avantajı, özellikle küçük demo projeleri için kodlamanın daha hızlı olabilmesidir. Dezavantajları, yazım hatalarına eğilimli olması ve dize ne kadar sık ​​kullanılırsa, bir yazım hatası kodu işini yapma şansı o kadar artar. Hiç istiyorsan değiştirmek sihirli dize, dizeleri üstlenmeden da dizeleri dokunmatik olabilecek üstlenmeden araçları beri değişkenleri üstlenmeden daha zor içerirler (bir alt dize gibi) sihirli dize ama vardır değil kendilerini sihirli dize ve gerektiği değil dokunulmamalıdır. Ayrıca, yeni geliştiricilerin aynı amaç için yeni sihirli dizeler icat etmeye başlamaması ve mevcut sihirli dizeleri ararken zaman kaybetmeyecek şekilde bir sözlük veya sihirli dizelerin dizini tutmanız gerekebilir.

Bu bağlamda, bir Enum sihirli dizelerden ve hatta küresel dize sabitlerinden daha iyi olabilir. Ayrıca, sabit dizeleri veya Numaralandırmaları kullandığınızda IDE'ler genellikle size bir tür kod yardımcısı (otomatik tamamlama, yeniden düzenleme, tümünü bulma vb.) Verir. Sihirli dizeler kullanırsanız IDE fazla yardım sunmaz.


Enumların dize değişmezlerinden daha iyi olduğunu kabul ediyorum. Ama o zaman bile, bir numaralandırma anahtarıyla bir "stateChangeRequest" çağırmak ya da doğrudan model üzerinde bir yöntemi çağırmak gerçekten daha mı iyi? Her iki durumda da, model ve görünüm bu noktada birleştirilir.
Philip

@Philip: O zaman, modeli ayrıştırmak ve o noktada görüntülemek için, bunu yapmak için bir çeşit kontrolör sınıfına ihtiyacınız olabilir ...
FrustratedWithFormsDesigner

@FrustratedWithFormsDesigner - Evet. Bir MVC mimarisi en ayrıştırılmış
cdeszaq

Doğru, başka bir katman onları ayırmaya yardımcı olacaksa, buna karşı çıkmam. Ancak bu katman hala statik olarak yazılabilir ve bunları bağlamak için dize veya numaralandırma iletileri yerine gerçek yöntemleri kullanabilir.
Philip

6

'Sektör deneyimi' kullanmak kötü bir argüman. Profesörünüzün bundan daha iyi bir argüman bulması gerekiyor :-).

Diğerlerinin de belirttiği gibi, sihirli Dizelerin kullanımı kesinlikle kaşlarını çattı, numaralandırmaların kullanılması çok daha güvenli kabul edildi. Bir enum'un anlamı ve kapsamı vardır , sihirli dizeler yoktur. Bunun yanı sıra, profesörünüzün endişeleri çözme biçiminin bugün kullanılandan daha eski ve daha kırılgan bir teknik olduğu düşünülmektedir.

@Backtodos'un buna cevap verirken bunu kapsadığını görüyorum, bu yüzden Inversion of Control (Bağımlılık Enjeksiyonu bir form olan) kullanarak endüstride Bahar çerçevesinden uzun süre önce çalışacağınıza dair fikrimi ekleyeceğim . ..) bu tip ayrılma ile başa çıkmanın daha modern bir yolu olarak kabul edilir.


2
Tamamen katılıyorum, akademinin endüstriden çok daha yüksek gereksinimleri olması gerekir. Akademi == en iyi teorik yol; Endüstri == en iyi pratik yol
Farmor

3
Ne yazık ki, akademide bu şeyleri öğretenlerin bazıları bunu endüstride kesemedikleri için yapıyor. Olumlu tarafı, akademideki bazı parlak ve bazı şirket ofisinde gizli tutulmamalıdır.
SinirliWithFormsDesigner

4

Oldukça açık olalım; olduğu kaçınılmaz orada bir birleştirme. Abone olunabilir bir konunun olması, mesajın geri kalanının doğası gibi (“tek dize” gibi) bir bağlantı noktasıdır. Bu göz önüne alındığında, soru, dizeler veya türler yoluyla yapıldığında kuplajın daha büyük olup olmadığından biri haline gelir. Bunun cevabı, zaman veya alan içinde dağıtılan kuplaj konusunda endişeleriniz olup olmadığına bağlıdır: mesajlar daha sonra okunmadan önce bir dosyada korunacak mı yoksa başka bir sürece gönderilecek mi (özellikle aynı dilde yazılmaz), dizeleri kullanmak işleri daha basit hale getirebilir. Dezavantajı hiçbir türü kontrol olmasıdır; blunders çalışma zamanına kadar algılanmayacak (ve bazen de o zaman bile olmayacak).

Java için bir azaltma / uzlaşma stratejisi, yazılı bir arayüz kullanmak olabilir, ancak bu yazılı arayüzün ayrı bir pakette olduğu yerlerde. Yalnızca Java interfaceve temel değer türlerinden (örn. Numaralandırmalar, istisnalar) oluşmalıdır . Bu pakette hiçbir arayüz uygulaması olmamalıdır . Daha sonra herkes buna karşı uygular ve mesajları karmaşık bir şekilde iletmek gerekirse, bir Java temsilcisinin belirli bir uygulaması gerektiğinde sihirli dizeleri kullanabilir. Ayrıca, kodu JEE veya OSGi gibi daha profesyonel bir ortama taşımayı kolaylaştırır ve test etme gibi küçük şeylere büyük ölçüde yardımcı olur ...


4

Profesörünüzün önerdiği şey "sihirli teller" kullanmaktır. Sınıfları birbirleri arasında "gevşek bir şekilde birleştirir" ve daha kolay değişikliklere izin verirken, bir anti-kalıptır; dizeler çok, çok nadiren kod talimatlarını içermek veya kontrol etmek için kullanılmalıdır ve kesinlikle gerçekleşmesi gerektiğinde, mantığı kontrol etmek için kullandığınız dizelerin değeri merkezi ve sürekli olarak tanımlanmalıdır, bu nedenle herhangi bir dize.

Nedeni çok basit; dizeler, sözdizimi veya diğer değerlerle tutarlılık açısından derleyici tarafından denetlenmez (en iyi durumda, kaçış karakterleri ve dize içindeki diğer dile özgü biçimlendirme ile ilgili doğru form için denetlenir). Bir dizeye istediğiniz her şeyi koyabilirsiniz. Bu nedenle, derlemek için umutsuzca kırılmış bir algoritma / program alabilirsiniz ve bir hata oluşana kadar çalışamaz. Aşağıdaki kodu düşünün (C #):

private Dictionary<string, Func<string>> methods;

private void InitDictionary() //called elsewhere
{
   methods = new Dictionary<string, Func<string>> 
      {{"Method1", ()=>doSomething()},
       {"MEthod2", ()=>doSomethingElse()}} //oops, fat-fingered it
}

public string RunMethod(string methodName)
{
   //very naive, but even a check for the key would generate a runtime error, 
   //not a compile-time one.
   return methods[methodName](); 
}

...

//this is what we thought we entered back in InitDictionary for this method...
var result = RunMethod("Method2"); //error; no such key

... tüm bu kodlar derleniyor, ilk deneyin, ama hata ikinci bir bakışta açıktır. Bu tür programlama için çok sayıda örnek vardır ve hepsi bu tür bir hataya tabidir, dizeleri sabit olarak tanımlarsanız (.NET'te sabitler kullanıldıkları her kütüphanenin manifestine yazıldığından, değerin "genel olarak" değişmesi için tanımlanan değer değiştirildiğinde hepsi yeniden derlenecektir). Hata derleme zamanında yakalanmadığından, çalışma zamanı testi sırasında yakalanmalıdır ve bu, yalnızca en mutlak arıza korumasında bulunan yeterli kod egzersizi ile yapılan birim testlerinde yalnızca% 100 kod kapsamı ile garanti edilir. , gerçek zamanlı sistemler.


2

Aslında, bu sınıflar hala sıkı sıkıya bağlı. Ancak şimdi, derleyici işler bozulduğunda size söyleyemeyecek şekilde sıkı sıkıya bağlılar!

Birisi "BicycleMake" i "BicyclesMake" olarak değiştirirse, kimse çalışma zamanına kadar işlerin bozulduğunu öğrenemez.

Çalışma zamanı hatalarını düzeltmek, zaman hatalarını derlemekten çok daha maliyetlidir - bu sadece her türlü kötülüktür.

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.