“Verileri temsil etmek için sınıf yerine haritayı kullan” -Rich Hickey


19

In Zengin Hickey tarafından bu videoda , Clojure yaratıcısı, o Java tamamlandı olarak yerine onu temsil edecek bir sınıf kullanmanın verileri temsil etmek haritayı kullanmak için önerir. Nasıl daha iyi olabileceğini anlamıyorum, çünkü API kullanıcısı sadece harita olarak gösteriliyorsa giriş anahtarlarının ne olduğunu nasıl bilebilir.

Örnek :

PersonAPI {
    Person addPerson(Person obj);
    Map<String, Object> addPerson(Map<String, Object> personMap);
}

İkinci işlevde, API kullanıcısı bir kişi oluşturmak için girdilerin neler olduğunu nasıl bilebilir?



Bunu da bilmek istiyorum ve örnek sorunun buna tam olarak cevap vermediğini hissediyorum.
sydan

Ben biliyorum ben SE yerde önce bu tartışmayı gördüm. JavaScript bağlamında olduğuna inanıyorum, ancak argümanlar aynıydı. Gerçi bulamıyorum.
Sebastian Redl

2
Clojure Lisp olduğu için Lisp'e uygun şeyler yapmalısınız. Java kullandığınızda, kodlayın ... iyi Java.
AK_

Yanıtlar:


12

Abartılı Özet (TM)

Birkaç şey elde edersiniz.

  • Prototip palet mirası ve klonlama
  • Dinamik yeni özellikler ekleme
  • Aynı sınıfın farklı sürümlerindeki nesnelerin (şartname düzeyleri) birlikte varlığı.
    • Daha yeni sürümlere (spesifikasyon seviyeleri) ait nesnelerin ekstra "isteğe bağlı" özellikleri olacaktır.
  • Özelliklerin tanıtımı, eski ve yeni
  • Doğrulama kurallarının tanıtımı (aşağıda tartışılmıştır)

Ölümcül bir dezavantaj var.

  • Derleyici yanlış yazılmış dizeleri sizin için kontrol etmez.
  • Otomatik yeniden düzenleme araçları, süslü olanlar için ödeme yapmazsanız, mülk anahtarı adlarını sizin için yeniden adlandırmaz.

Mesele şu ki, içgözlem kullanarak içgözlem alabilirsiniz. Genellikle olan budur:

  • Yansımayı etkinleştir.
  • Projenize büyük bir introspection kütüphanesi ekleyin.
  • Çeşitli nesne yöntemlerini ve özelliklerini nitelikler veya ek açıklamalarla işaretleyin.
  • İç gözlem kütüphanesinin sihri yapmasına izin verin.

Başka bir deyişle, FP ile arayüz kurmanız gerekmiyorsa, Rich Hickey'in tavsiyelerini almanız gerekmez.

Son olarak, ama en az değil (en güzel), Stringözellik anahtarı olarak kullanmak en açık mantıklı olsa da, s'yi kullanmak zorunda değilsiniz String. Android ™ dahil olmak üzere birçok eski sistem, sınıfları, özellikleri, kaynakları vb. Belirtmek için tam çerçeve kimliklerini tüm çerçeve boyunca kapsamlı bir şekilde kullanır.

Android, Google Inc.'in ticari markasıdır.


Her iki dünyayı da mutlu edebilirsiniz.

Java dünyası için alıcıları ve ayarlayıcıları her zamanki gibi uygulayın.

FP dünyası için,

  • Object getPropertyByName(String name)
  • void setPropertyByName(String name, Object value) throws IllegalPropertyChangeException
  • List<String> getPropertyNames()
  • Class<?> getPropertyValueClass(String name)

Bu Fonksiyonun içerisinde evet, ama ... akıllı eklenti kullanarak, sizin için dolduracaktır IDE eklentileri çirkin kod vardır okur kodunuzu.

Her şeyin Java tarafı her zamanki gibi performans gösterecektir. Kodun çirkin kısmını asla kullanmayacaklar . Hatta Javadoc'tan gizlemek isteyebilirsiniz.

Dünyanın FP tarafı istedikleri "leet" kodunu yazabilirler ve genellikle kodun yavaş olması konusunda size bağırmazlar.


Genel olarak, nesnenin yerine bir haritanın (özellik çantası) kullanılması yazılım geliştirmede yaygındır. İşlevsel programlamaya veya belirli bir dil türüne özgü değildir. Herhangi bir dil için deyimsel bir yaklaşım olmayabilir, ancak bunu gerektiren durumlar vardır.

Özellikle, serileştirme / serileştirme genellikle benzer bir teknik gerektirir.

"Nesne olarak harita" ile ilgili genel düşünceler.

  1. Yine de böyle bir "nesne olarak eşleme" işlevini doğrulamak için bir işlev sağlamanız gerekir. Fark, "nesne olarak eşle" seçeneğinin daha esnek (daha az kısıtlayıcı) doğrulama kriterlerine izin vermesidir.
  2. "Nesne olarak eşle" seçeneğine kolayca ekleme alanları ekleyebilirsiniz.
  3. Geçerli bir nesnenin minimum gereksiniminin bir belirtimini sağlamak için aşağıdakileri yapmanız gerekir:
    • Haritada beklenen "minimum düzeyde gerekli" anahtar kümesini listeleyin
    • Değeri doğrulanması gereken her anahtar için bir değer doğrulama işlevi sağlayın
    • Birden fazla anahtar değerini kontrol etmesi gereken doğrulama kuralları varsa, bunu da sağlayın.
    • Avantajı nedir? Belirtimi bu şekilde sağlamak içgözlemlidir: minimum düzeyde gerekli anahtar kümesini sorgulamak ve her anahtar için doğrulama işlevini elde etmek için bir program yazabilirsiniz.
    • OOP'de, bunların tümü "kapsülleme" adı altında kara bir kutuya toplanır. Makine tarafından okunabilir doğrulama mantığı yerine, arayan yalnızca insan tarafından okunabilen "API dokümantasyonunu" okuyabilir (iyi ki varsa).

commonplacebana biraz güçlü geliyor. Demek istediğim, tarif ettiğin gibi kullanılıyor, ama aynı zamanda kütüphanelerin saklanmak için en lanetlerini denediği kötü şöhretli / kırılgan şeylerden biri (bayt dizileri veya çıplak işaretçiler gibi).
Telastyn

@Telastyn Bu "bin yılanın çirkin başı" tipik olarak iki sistem arasındaki iletişim sınırında meydana gelir, burada bir nedenden dolayı iletişim veya süreçler arası kanal nesnelerin bozulmadan ışınlanmasına izin vermez. Protokol Tamponları gibi yeni teknikler haritanın nesne olarak bu arkaik kullanım durumunu neredeyse ortadan kaldırdı. Hala geçerli başka kullanım durumları olabilir, ancak bu konuda çok az bilgim var.
rwong

2
Ölümcül sakıncalar konusunda hemfikir olun. Ancak, "kolay yazım hatası" ve "yeniden düzenleme zor" özellik anahtar adları, mümkün olduğunca sabit veya numaralandırmalarda tutulursa , bu sorun ortadan kalkar . Tabii ki, genişletilebilirliği bazı
sınırlıyor

Eğer "bir ölümcül dezavantaj" gerçekten ölümcül ise, neden bazı insanlar etkili bir şekilde kullanabilir. Ayrıca, sınıflar ve statik yazma diktir - dinamik olarak yazılmış olsa bile sınıfları Clojure'da tanımlayabilirsiniz.
Nathan Davis

@NathanDavis (1) Cevabımın statik yazım perspektifinden (C #) yazıldığını itiraf ediyorum ve bu cevabı yazdım çünkü askerin aynı bakış açısını paylaşıyorum. FP merkezli bir bakış açısına sahip olmadığımı itiraf ediyorum. (2) SE.SE'ye hoş geldiniz ve Clojure'da saygın bir figür olduğunuzdan, mevcut olanlar tatmin edici değilse lütfen kendi cevabınızı yazmak için zaman ayırın. Downvotes ünleri çıkarır ve yeni cevaplar, itibarları hızla artıran upvotes çeker. (3) "Tamamlanmamış nesneler" in nasıl yararlı olabileceğini görebiliyorum - belirli bir nesne (isim, avatar) için 2 özelliği sorgulayabilir ve gerisini dışarıda bırakabilirsiniz.
rwong

9

Ne hakkında konuştuğunu gerçekten bilen biri tarafından mükemmel bir konuşma. Okuyucuların her şeyi izlemelerini öneririm. Sadece 36 dakika sürüyor.

Ana noktalarından biri, sadeliğin daha sonra değişim fırsatları yaratmasıdır. A'yı temsil edecek bir sınıf seçmek Person, belirttiğiniz gibi statik olarak doğrulanabilir bir API oluşturmanın hemen faydasını sağlar, ancak bu, fırsatları sınırlama veya daha sonra değişim ve yeniden kullanım maliyetlerini artırma maliyetiyle birlikte gelir.

Amacı, sınıfı kullanmanın makul bir seçim olabileceğidir, ancak maliyetinin tam farkındalığıyla gelen bilinçli bir seçim olmalıdır ve programcılar geleneksel olarak bu maliyetleri dikkate almak yerine, bu maliyetleri fark etmek için çok zayıf bir iş çıkarırlar. Bu seçenek, gereksinimleriniz arttıkça yeniden değerlendirilmelidir.

Aşağıdakiler, bir Personnesne listesi kullanmaya kıyasla bir harita listesi kullanmanın potansiyel olarak daha basit olan bazı kod değişiklikleri (bir veya iki tanesi konuşmada belirtilmiştir) :

  • Bir kişiyi REST sunucusuna gönderme. (Bir Mapilkel öğelerin iletilebilir bir biçime yerleştirilmesi için oluşturulan bir işlev oldukça yeniden kullanılabilir ve bir kitaplıkta bile sağlanabilir. Bir Personnesnenin aynı işi gerçekleştirmek için özel koda gereksinimi olabilir).
  • İlişkisel veritabanı sorgusundan otomatik olarak bir kişi listesi oluşturun. (Yine, bir genel ve yüksek oranda yeniden kullanılabilir fonksiyon).
  • Bir kişiyi görüntülemek ve düzenlemek için otomatik olarak bir form oluşturun.
  • Bir öğrenciye karşı bir çalışan gibi oldukça homojen olmayan kişi verileriyle çalışmak için ortak işlevleri kullanın.
  • Belirli bir posta kodunda bulunan tüm kişilerin bir listesini alın.
  • Belirli bir posta kodundaki tüm işletmelerin bir listesini almak için bu kodu yeniden kullanın.
  • Diğer müşterileri etkilemeden bir kişiye müşteriye özgü bir alan ekleyin.

Bu tür sorunları her zaman çözeriz ve onlar için kalıplara ve araçlara sahibiz, ancak başlangıçta daha basit, daha esnek bir veri temsilinin seçilmesinin işimizi kolaylaştıracağını düşünmek nadiren durur.


Bunun için bir isim var mı? Diyelim ki, Nesne-Özellik Eşleme veya Nesne Özelliği Eşleme (ORM ile aynı satır boyunca)?
rwong

4
Choosing a class to represent a Person provides the immediate benefit of creating a statically-verifiable API... but that comes with the cost of limiting opportunities or increasing costs for change and reuse later on.Yanlış ve inanılmaz derecede ihtiyatlı. Daha sonra değiştirme fırsatınızı geliştirir , çünkü bir kırılma değişikliği yaptığınızda, derleyici tüm kod tabanınızı hızlandırmak için güncellenmesi gereken her yeri otomatik olarak bulur ve işaret eder. Dinamik kodda, bunu yapamayacağınız yer, gerçekten önceki seçimlerle birleşiyorsunuz!
Mason Wheeler

4
@MasonWheeler: Gerçekten söylediğiniz şey, daha dinamik (ve daha gevşek yazılan) veri yapıları üzerinde derleme zamanı tür güvenliğine değer vermenizdir.
Robert Harvey

1
Çok biçimlilik OOP ile sınırlı bir kavram değildir. Haritalarda kapsayıcı polimorfizm (elemanlar haritanın işleyebileceği bir tür alt türler ise) veya geçici polimorfizme (elemanlar sendikalar etiketlenmişse) sahip olabilirsiniz. Bunlar içseldir. Bir harita üzerinde yapılabilecek işlemler de polimorfik olabilir. Öğeler üzerinde daha yüksek dereceli fonksiyon kullandığımızda veya gönderim sırasında geçici olarak parametrik polimorfizm. Kapsülleme, ad alanları veya diğer görünürlük yönetimi biçimleriyle gerçekleştirilebilir. Temel olarak nesnelerin izolasyonu, veri türlerine işlem atamaya eşit değildir.
siefca

1
@GillBates bunu neden söyledin? Bu sanal yöntemleri "Harita'nın içine" koyma fırsatını kaçırıyorsunuz - ama Rich Hickey'in tam olarak bahsettiği şey, "ActiveObjects" gerçekten bir anti-desen. Verilere ne olduğu (veri) gibi davranmalı ve davranışla iç içe olmamalıdır. Endişeleri birbirinden ayırarak elde edilecek büyük basitlik avantajları vardır.
Virgil

4
  • Verilerin çok az davranışı veya hiç davranışı yoksa, değişmesi muhtemel esnek içerik varsa, bir Harita kullanın. N alanları, N ayarlayıcıları ve N alıcıları olan bir Anemik Etki Alanı Modelinden oluşan tipik bir "javabean" veya "Veri Nesnesi" IMO, zaman kaybıdır. Başkalarını yüceltilmiş yapınızla süslü bir sınıfta sararak etkilemeye çalışmayın. Dürüst olun, niyetlerinizi netleştirin ve bir Harita kullanın. (Veya alan adınız, JSON veya XML nesnesi için herhangi bir anlam ifade ediyorsa)

  • Verilerin önemli fiili davranışları varsa (diğer bir deyişle yöntemler ( Söyle, Sorma )), bir sınıf kullanın. Ve gerçek Nesne Tabanlı programlama :-) kullanmak için kendinizi arkada pat.

  • Verilerde çok sayıda önemli doğrulama davranışı ve zorunlu alanlar varsa, bir sınıf kullanın.

  • Verilerin orta miktarda doğrulama davranışı varsa, bu sınırdadır.

  • Veriler mülk değişikliği olaylarını tetiklerse, bu bir Harita ile daha kolay ve daha az sıkıcıdır. Sadece küçük bir alt sınıf yaz.

  • Bir Harita kullanmanın temel dezavantajı, kullanıcının değerleri Dizeler, ints, Foos, vb.'ye dökmesi gerektiğidir. Veya haritayı ilgili alıcılarla saran bir yardımcı sınıf düşünün.


1
Aslında, Rich Hickey'in iddia ettiği şey, eğer verilerin önemli bir gerçek davranışı varsa ... muhtemelen bütün "tasarım" işini yanlış yapıyorsunuzdur. Veri "bilgi" dir. Gerçek dünyada bilgi "verilerin saklandığı bir yer" DEĞİLDİR. Bilginin "bilginin nasıl değiştiğini kontrol eden işlemleri" yoktur. İnsanlara nerede depolandığını söyleyerek bilgi aktarmıyoruz. Nesneye yönelik metaforlar SOMETIMES dünyanın uygun bir modelidir ... ama çoğu zaman değil. Diyor ki - "ypur problemini düşün". Her şey bir nesne değildir - birkaç şey vardır.
Virgil

0

A için API'nin mapiki düzeyi vardır.

  1. Haritalar için API.
  2. Uygulama kuralları.

API, konvansiyon ile haritada açıklanabilir. Örneğin, çift :api api-validateharitaya yerleştirilebilir veya :api-foo validate-fookongre olabilir. Harita bile saklanabilir api api-documentation-link.

Kuralların kullanılması, programcının harita olarak uygulanan "türler" arasında erişimi standartlaştıran, alana özel bir dil oluşturmasına olanak tanır. Kullanmak (keys map), çalışma zamanında özelliklerin belirlenmesine olanak tanır.

Haritalar hakkında büyülü bir şey yok ve nesneler hakkında büyülü bir şey yok. Hepsi sevk.

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.