Üye: Etki alanı nesnesine karşı benzersiz kimlikler kullanma


10

Etki alanı nesnesini veya benzersiz bir kimliği yöntem / işlev parametresi olarak kullanmam gerekip gerekmediğine ilişkin birkaç yararlı yanıttan sonra, tanıtıcı ve etki alanı nesnesini bir yöntem parametresi olarak kullandığımdan sonra , benzer bir sorum var: üyeler (önceki sorular tartışması başaramadı bunu kapsar). Üye olarak benzersiz kimlikleri üye olarak nesne olarak kullanmanın avantajları ve dezavantajları nelerdir. Scala / C # / Java gibi güçlü yazılan dillere başvuruyorum. Olmalı mıyım (1)

User( id: Int, CurrentlyReadingBooksId: List[Int])
Book( id: Int, LoanedToId: Int )

veya (2), (1) 'e tercih ettikten sonra: Her şey için türleri tanımlamalı mıyız?

User( id: UserId, CurrentlyReadingBooksId: List[ BookId] )
Book( id: BookId, LoanedToId: UserId )

veya (3)

User( id: Int, CurrentlyReadingBooks: List[Book]) 
Book( id: Int, LoanedTo: User)

Nesneye (3) sahip olmanın faydalarını düşünemesem de, ID (2) ve (1) 'e sahip olmanın faydaları DB'den User nesnesini oluşturduğumda, Book nesnesini oluşturmak zorunda olmamamdır. sonuç olarak sonsuz bir zincir oluşturarak Kullanıcı nesnesinin kendisine bağlı olabilir. RDBMS ve No-SQL (farklıysa) için bu soruna genel bir çözüm var mı?

Şimdiye kadar bazı cevaplara dayanarak, sorumu yeniden ifade ediyorum: (sarılmış türlerde olması gereken kimliklerin kullanımı ile) 1) Her zaman kimlikler kullanılsın mı? 2) Her zaman Nesneler kullanılsın mı? 3) Serileştirme ve serileştirme işlemlerinde yineleme riski olduğunda kimlikler kullanın, ancak nesneleri başka şekilde mi kullanıyorsunuz? 4) Başka bir şey var mı?

DÜZENLEME: Nesnelerin her zaman veya bazı durumlarda kullanılması gerektiğine yanıt verirseniz, lütfen diğer yanıtlayıcıların gönderdiği en büyük endişeye cevap verdiğinizden emin olun => DB'den veri alma


1
İyi soru için teşekkürler, bunu ilgiyle takip etmeyi dört gözle bekliyorum. Kullanıcı adınızın "user18151" olduğu için utanç verici, bu tür kullanıcı adına sahip kişiler bazıları tarafından göz ardı ediliyor :)
bjfletcher

@bjfletcher Teşekkür ederim. Bu nagging algısını kendim yaptım, ama neden bana hiç olmadı!
0fnt

Yanıtlar:


7

Kimlik olarak Etki Alanı Nesneleri bazı karmaşık / ince sorunlar yaratır:

Seri hale / Seri kaldırma

Nesneleri anahtar olarak saklarsanız, nesne grafiğini serileştirmek son derece karmaşık hale gelir. stackoverflowÖzyineleme nedeniyle JSON veya XML'ye saf bir serileştirme yaparken hata alırsınız . Daha sonra, nesne örneğini serileştirmek ve özyineleme oluşturmak yerine, gerçek nesneleri kendi kimliklerini kullanmak için dönüştüren özel bir serileştirici yazmanız gerekir.

Nesneleri tür güvenliği için geçirin, ancak yalnızca kimlikleri saklayın, ardından çağrıldığında ilgili varlığı tembel yükleyen bir erişimci yönteminiz olabilir. İkinci düzey önbellekleme sonraki çağrılarla ilgilenir.

İnce referans sızıntıları:

Etki alanı nesnelerini, sizin gibi yapıcılarda kullanırsanız, etkin olarak kullanılmayan nesneler için belleğin geri kazanılmasına izin vermek çok zor olacak dairesel başvurular oluşturacaksınız.

İdeal Durum:

Opak kimlikleri vs int / long:

A id, neyi tanımladığı hakkında hiçbir bilgi taşımayan tamamen opak bir tanımlayıcı olmalıdır. Ancak, sistemde geçerli bir tanımlayıcı olduğunu doğrulamalıdır.

Ham türler bunu kırıyor:

int, longVe StringRDBMS sisteme tanımlayıcılar için en yaygın olarak kullanılan ham türleridir. Onlarca yıl öncesine dayanan uzun bir pratik nedenler tarihi vardır ve hepsi spaceya tasarruf timeya da tasarruf ya da her ikisine de uyan tavizlerdir .

Sıralı kimlikler en kötü suçlulardır:

Sıralı bir kimlik kullandığınızda, geçici olarak semantik bilgileri kimlik olarak varsayılan olarak paketlersiniz. Kullanılana kadar kötü değil . İnsanlar kimliğin anlamsal kalitesini sıralayan veya filtreleyen iş mantığı yazmaya başladığında, gelecekteki koruyucular için bir acı dünyası kuruyorlar.

String Alanlar sorunludur, çünkü saf tasarımcılar içeriğe, genellikle geçici anlambilimde de bilgi toplarlar.

Bunlar çünkü, hem de dağıtılmış veri sistemi oluşturmak mümkün değildir yapmak 12437379123olduğunu değil benzersiz global. Dağıtılmış bir sistemdeki başka bir düğümün aynı numaraya sahip bir kayıt oluşturma şansı, bir sistemde yeterli veri elde ettiğinizde neredeyse garanti edilir.

Sonra hackler etrafında çalışmaya başlar ve her şey buharda bir karmaşaya dönüşür.

Devasa dağıtılmış sistemleri ( kümeleri ) göz ardı etmek, verileri diğer sistemlerle de paylaşmaya çalıştığınızda tam bir kabus haline gelir. Özellikle diğer sistem kontrolünüz altında değilse.

Aynı problemle, kimliğinizi global olarak nasıl benzersiz hale getireceğinizle sonuçlanırsınız.

UUID bir nedenle oluşturuldu ve standartlaştırıldı:

UUIDkullandığınız şekle bağlı olarak yukarıda listelenen tüm sorunlardan muzdarip olabilir Version.

Version 1benzersiz bir kimlik oluşturmak için bir MAC adresi ve zamanı kullanır. Bu kötüdür, çünkü konum ve zaman hakkında anlamsal bilgi taşır. Bu kendi başına bir sorun değildir, saf geliştiriciler iş mantığı için bu bilgilere güvenmeye başlarlar. Bu ayrıca herhangi bir saldırı girişiminde kullanılabilecek bilgileri de sızdırıyor.

Version 2bir kullanıcı UIDya da GIDdomian kullanır ya UIDda GUIzamanın yerine veri sızıntısı ve bu bilgilerin iş mantığında kullanılması riski Version 1kadar kötüdür Version 1.

Version 3benzerdir, ancak MAC adresini ve zamanı kesinlikle semantik anlamı olan bir şeyden oluşan bir MD5karma ile değiştirir byte[]. Endişelenecek veri kaçağı yoktur, byte[]kurtarılamaz UUID. Bu, belirli bir şekilde UUIDörnek formu ve dış anahtar belirleyici bir şekilde oluşturmanın iyi bir yolunu sunar .

Version 4 sadece iyi bir çözüm olan rastgele sayılara dayanır, kesinlikle semantik bilgi içermez, ancak deterministik olarak yeniden oluşturulamaz.

Version 5gibi Version 4ama sha1yerine kullanır md5.

Etki Alanı Anahtarları ve İşlem Veri Anahtarları

Etki alanı nesne kimlikleri için tercihim, teknik nedenlerden dolayı kullanmak Version 5veya Version 3kısıtlanmış Version 5olması.

Version 3 birçok makineye yayılmış işlem verileri için mükemmeldir.

Alan tarafından kısıtlanmadıkça bir UUID kullanın:

Benzersiz, garantili bir veritabanından veri dökümü ve farklı etki alanı verilerine atıfta bulunan yinelenen kimlikler hakkında endişelenmeniz gerekmediği başka bir veritabanına yeniden yükleme.

Version 3,4,5 tamamen opak ve bu şekilde olmalı.

A ile birincil anahtar olarak tek bir sütuna sahip UUIDolabilirsiniz ve daha sonra doğal bir bileşik birincil anahtarın ne olacağı için bileşik benzersiz dizinlere sahip olabilirsiniz.

Depolama alanı da olmak zorunda değildirCHAR(36) . UUIDHala endekslenebilir olduğu sürece belirli bir veritabanı için yerel bir bayt / bit / sayı alanında saklayabilirsiniz .

miras

Ham türleriniz varsa ve bunları değiştiremiyorsanız, yine de kodunuzda soyutlayabilirsiniz.

Bir kullanma Version 3/5arasında UUIDsende geçebilir Class.getName()+ String.valueOf(int)bir şekilde byte[]ve yeniden oluşturulabilir ve deterministik bir opak referans anahtarı var.


Sorumda net olmasaydım çok üzgünüm ve daha da kötüsünü (ya da gerçekten iyi) hissediyorum çünkü bu harika ve iyi düşünülmüş bir cevap ve açıkça zaman harcadın. Maalesef soruma uymuyor, belki de kendi başına bir soruyu hak ediyor? "Alan adı nesnem için kimlik alanı oluştururken nelere dikkat etmeliyim?"
0fnt

Açık bir açıklama ekledim.

Şimdi anladım. Cevaba zaman ayırdığınız için teşekkürler.
0fnt

1
Btw, AFAIK nesil çöp toplayıcıları (ki bu günlerde hâkim GC sisteminin ne olduğuna inanıyorum) GC'nin dairesel referanslarında çok fazla zorluk yaşamamalı.
0fnt

1
eğer C-> A -> B -> Ave Bbir konur Collectionsonra Ave tüm çocuklar hala ulaşılabilir, bunlar tamamen belirgin değildir ve ince yol açabilir sızıntılar . GCproblemlerin en azı, grafiğin serileştirilmesi ve serileştirilmesi karmaşıklığın bir kabusu.

2

Evet, her iki şekilde de faydalar var ve ayrıca bir uzlaşma da var.

List<int>:

  • Bellek tasarrufu
  • Türün daha hızlı başlatılması User
  • Verileriniz ilişkisel bir veritabanından (SQL) geliyorsa, kullanıcı almak için iki tabloya erişmeniz gerekmez, yalnızca Userstablo

List<Book>:

  • Bir kitaba erişmek kullanıcıdan daha hızlıdır, kitap önceden belleğe yüklenmiştir. Daha sonraki işlemleri daha hızlı almak için daha uzun bir başlangıç ​​yapmayı göze alabiliyorsanız bu hoş.
  • Verileriniz HBase veya Cassandra gibi bir belge deposu veritabanından geliyorsa, okunan kitapların değerleri büyük olasılıkla Kullanıcı kaydındadır, böylece "siz kullanıcıyı alırken" kitapları kolayca alabilirsiniz.

Eğer gideceğim herhangi bir bellek veya CPU endişeniz yoksa List<Book>, Userörnekleri kullanan kod daha temiz olacaktır.

Uzlaşma:

Linq2SQL kullanırken, Kullanıcı varlığı için oluşturulan kod, eriştiğinizde EntitySet<Book>tembel olarak yüklenen bir koda sahip olacaktır . Bu, kodunuzu temiz ve Kullanıcı örneğini küçük tutmalıdır (bellek alanı akıllıca olmalıdır).


Bir çeşit önbellekleme varsayıldığında, önyükleme faydası geçersiz olacaktır. Cassandra / HBase kullanmadım, bu yüzden onlar hakkında konuşamam ama Linq2SQL çok özel bir durum (her ne kadar tembel yüklemenin bu özel durumda ve genel durumda bile sonsuz zincirleme durumunu nasıl önleyeceğini görmüyorum)
0fnt

Linq2SQL örneğinde gerçekten hiçbir performans avantajı elde edemezsiniz, sadece daha temiz kod. Cassandra / HBase gibi bir doküman mağazasından bir-çok sayıda varlık alırken, işlem süresinin büyük çoğunluğu kaydı bulmak için harcanır, böylece orada olduğunuzda birçok varlığı da alabilirsiniz (kitaplar, bu örnek).
ytoledano

Emin misiniz? Kitap ve Kullanıcıları ayrı ayrı normalleştirilmiş olarak saklasam bile? Bana göre sadece ağ gecikmesi ekstra maliyet olmalı gibi görünüyor. Her durumda, RDBMS örneği genel olarak nasıl işlenir? (Bunu açıkça belirtmek için soruyu düzenledim)
0fnt

1

Kısa ve basit bir kural:

ID'ler DTO'larda kullanılır .
Nesne başvuruları genellikle Etki Alanı Mantığı / İş Mantığı ve kullanıcı arabirimi katmanı nesnelerinde kullanılır.

Bu daha büyük ve yeteri kadar projelerde ortak mimari. Bu iki tür nesneye dönüşen ve ilerleyen haritacılarınız olacak.


Uğradığınız ve yanıtladığınız için teşekkür ederiz. Ne yazık ki, wiki bağlantısı sayesinde ayrımı anlasam da, bunu pratikte hiç görmedim (büyük uzun vadeli projelerle hiç çalışmadım). Aynı nesnenin iki farklı amaç için iki şekilde temsil edildiği bir örneğiniz olur mu?
0fnt

İşte haritalandırma ile ilgili gerçek bir soru: stackoverflow.com/questions/9770041/dto-to-entity-mapping-tool - ve bunun gibi kritik makaleler var: rogeralsing.com/2013/12/01/…
herzmeister

Gerçekten yararlı, teşekkürler. Maalesef, dairesel referanslarla veri yüklemenin nasıl çalışacağını hala anlamıyorum? örneğin, bir Kullanıcı bir Kitabı ve Kitap aynı kullanıcıyı ifade ediyorsa, bu nesneyi nasıl yaratırsınız?
0fnt

İçine bak Depo desen . Bir BookRepositoryve bir UserRepository. Her zaman arayacak myRepository.GetById(...)veya benzeyeceksiniz ve havuz ya nesneyi oluşturacak ve değerlerini bir veri deposundan yükleyecek ya da önbellekten alacaktır. Ayrıca, alt nesneler çoğunlukla tembel yüklenir, bu da inşaat zamanında doğrudan dairesel referanslarla uğraşmayı önler.
herzmeister
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.