Saat ini saya sedang mengerjakan sistem di mana ada Pengguna, dan setiap pengguna memiliki satu atau beberapa peran. Apakah praktik yang baik untuk menggunakan nilai Daftar Enum pada Pengguna? Saya tidak bisa memikirkan sesuatu yang lebih baik, tetapi ini tidak terasa baik-baik saja.
enum Role{
Admin = 1,
User = 2,
}
class User{
...
List<Role> Roles {get;set;}
}
Jawaban:
TL; DR: Biasanya merupakan ide yang buruk untuk menggunakan koleksi enum karena sering mengarah pada desain yang buruk. Kumpulan enum biasanya membutuhkan entitas sistem yang berbeda dengan logika spesifik.
Penting untuk membedakan antara beberapa kasus penggunaan enum. Daftar ini hanya dari atas kepala saya sehingga mungkin ada lebih banyak kasus ...
Contoh-contohnya semuanya dalam C #, saya kira bahasa pilihan Anda akan memiliki konstruksi yang sama atau mungkin bagi Anda untuk menerapkannya sendiri.
1. Hanya nilai tunggal yang valid
Dalam hal ini, nilainya eksklusif, misalnya
Tidak valid memiliki beberapa pekerjaan yang keduanya
Pending
danDone
. Karenanya hanya satu dari nilai-nilai ini yang valid. Ini adalah kasus penggunaan enum yang baik.2. Kombinasi nilai valid.
Kasus ini juga disebut flags, C # menyediakan
[Flags]
atribut enum untuk bekerja dengannya. Idenya dapat dimodelkan sebagai satu setbool
s ataubit
s dengan masing-masing sesuai dengan satu anggota enum. Setiap anggota harus memiliki nilai kekuatan dua. Kombinasi dapat dibuat menggunakan operator bitwise:Menggunakan koleksi anggota enum adalah pembunuhan berlebihan dalam kasus seperti itu karena setiap anggota enum hanya mewakili satu bit yang ditetapkan atau tidak disetel. Saya kira sebagian besar bahasa mendukung konstruksi seperti ini. Kalau tidak, Anda dapat membuatnya (misalnya menggunakan
bool[]
dan mengatasinya dengan(1 << (int)YourEnum.SomeMember) - 1
).a) Semua kombinasi valid
Meskipun ini ok dalam beberapa kasus sederhana, kumpulan objek mungkin lebih tepat karena Anda sering memerlukan informasi atau perilaku tambahan berdasarkan jenisnya.
(catatan: ini mengasumsikan Anda hanya benar-benar peduli dengan rasa es krim - bahwa Anda tidak perlu memodelkan es krim sebagai koleksi sendok dan kerucut)
b) Beberapa kombinasi nilai valid dan beberapa tidak
Ini adalah skenario yang sering terjadi. Yang mungkin terjadi adalah Anda memasukkan dua hal yang berbeda ke dalam satu enum. Contoh:
Sekarang walaupun benar-benar valid untuk keduanya
Vehicle
danBuilding
memilikiDoor
s danWindow
s, tidak biasa bagiBuilding
s untuk memilikiWheel
s.Dalam hal ini, akan lebih baik untuk memecah enum menjadi beberapa bagian dan / atau memodifikasi hirarki objek untuk mencapai kedua kasus # 1 atau # 2a).
Pertimbangan desain
Entah bagaimana, enum cenderung bukan elemen penggerak dalam OO karena jenis entitas dapat dianggap mirip dengan informasi yang biasanya disediakan oleh enum.
Ambil contoh
IceCream
sampel dari # 2,IceCream
entitas bukannya bendera memiliki koleksiScoop
objek.Pendekatan yang kurang murni adalah untuk
Scoop
memilikiFlavor
properti. Pendekatan murni akan untukScoop
menjadi kelas dasar abstrak untukVanillaScoop
,ChocolateScoop
, ... kelas sebagai gantinya.Intinya adalah bahwa:
1. Tidak semua yang merupakan "tipe sesuatu" harus enum
2. Ketika beberapa anggota enum bukan bendera yang valid dalam beberapa skenario, pertimbangkan untuk membagi enum menjadi beberapa enum yang berbeda.
Sekarang untuk contoh Anda (sedikit berubah):
Saya pikir case yang tepat ini harus dimodelkan sebagai (note: not really extensible!):
Dengan kata lain - itu adalah implisit, bahwa itu
User
adalahUser
, info tambahan adalah apakah dia seorangAdmin
.Jika Anda bisa memiliki peran ganda yang tidak eksklusif (misalnya
User
bisaAdmin
,Moderator
,VIP
, ... pada saat yang sama), yang akan menjadi saat yang tepat untuk menggunakan bendera enum atau kelas dasar ABSTRAK atau interface.Menggunakan kelas untuk mewakili
Role
petunjuk mengarah ke pemisahan tanggung jawab yang lebih baik di mana aRole
dapat memiliki tanggung jawab untuk memutuskan apakah ia dapat melakukan tindakan yang diberikan.Dengan enum Anda harus memiliki logika di satu tempat untuk semua peran. Yang mengalahkan tujuan OO dan membawa Anda kembali ke keharusan.
Bayangkan bahwa seorang
Moderator
memiliki hak edit danAdmin
memiliki hak mengedit dan menghapus.Pendekatan Enum (dipanggil
Permissions
agar tidak mencampuradukkan peran dan izin):Pendekatan kelas (ini jauh dari sempurna, idealnya, Anda menginginkan
IAction
pola pengunjung dalam tetapi postingan ini sudah sangat besar ...):Menggunakan enum mungkin merupakan pendekatan yang dapat diterima (misalnya kinerja). Keputusan di sini tergantung pada persyaratan sistem yang dimodelkan.
sumber
[Flags]
menyiratkan semua kombinasi valid lebih dari int menyiratkan keempat miliar nilai jenis itu valid. Ini hanya berarti mereka dapat digabungkan dalam satu bidang - pembatasan apa pun pada kombinasi dimiliki oleh logika tingkat tinggi.[Flags]
, Anda harus mengatur nilai ke kekuatan dua, atau jika tidak, itu tidak akan berfungsi seperti yang diharapkan.Mengapa tidak menggunakan Set? Jika menggunakan Daftar:
Jika Anda khawatir tentang kinerja, maka, misalnya di Jawa, ada
EnumSet
yang diimplementasikan sebagai array panjang tetap boolean (elemen boolean ke-i menjawab pertanyaan apakah nilai Enum ke-i ada di set ini atau tidak). Sebagai contohEnumSet<Role>
,. Juga lihatEnumMap
. Saya menduga bahwa C # memiliki sesuatu yang serupa.sumber
EnumSet
diimplementasikan sebagai bidang bit.HashSet<MyEnum>
flags enums: stackoverflow.com/q/9077487/87698FlagsAttribute
, yang memungkinkan Anda menggunakan operator bitwise untuk menyelesaikan enum. Kedengarannya mirip dengan JavaEnumSet
. msdn.microsoft.com/en-US/LIBRARY/system.flagsattribute EDIT: Seharusnya saya melihat satu jawaban! ini memiliki contoh yang bagus tentang ini.Tulis enum Anda sehingga Anda bisa menggabungkannya. Dengan menggunakan basis 2 eksponensial, Anda dapat menggabungkan semuanya dalam satu enum, memiliki 1 properti, dan dapat memeriksanya. Enum Anda harus lile ini
sumber
EnumSet
yang mengimplementasikan ini untukenum
s. Anda memiliki semua aritmatika boolean yang sudah diabstraksikan, ditambah beberapa metode lain untuk membuatnya lebih mudah digunakan, ditambah memori yang kecil dan kinerja yang baik.[flags]
atribut, yang dieksplorasi oleh @ Zdeněk Jelínek di posnya .Jawaban singkat : Ya
Jawaban singkat yang lebih baik : Ya, enum mendefinisikan sesuatu di domain.
Jawaban waktu-desain : Buat dan gunakan kelas, struktur, dll. Yang memodelkan domain dari segi domain itu sendiri.
Jawaban waktu pengkodean : Inilah cara sling kode sling ...
Pertanyaan-pertanyaan yang disimpulkan :
Haruskah saya menggunakan string?
Haruskah saya menggunakan kelas lain?
Apakah
Role
daftar enum cukup untuk digunakanUser
?WTF Bob?
Ini adalah pertanyaan desain yang dibingkai dalam teknis bahasa pemrograman.
enum
adalah cara yang baik untuk mendefinisikan "Peran" dalam model Anda. MakaList
peran adalah hal yang baik.enum
jauh lebih unggul dari string.Role
adalah deklarasi SEMUA peran yang ada di domain."A"
"d"
"m"
"i"
"n"
, dalam urutan itu. Ini tidak ada artinya sejauh menyangkut domain.Setiap kelas yang mungkin Anda rancang untuk memberikan konsep
Role
kehidupan - fungsionalitas - dapat memanfaatkanRole
enum dengan baik.Role
properti yang memberi tahu peran seperti apa instance kelas ini.User.Roles
daftar wajar ketika kita tidak perlu, atau tidak ingin, benda peran instantiated.RoleFactory
kelas; dan, tidak signifikan, kepada pembaca kode.sumber
Itu bukan sesuatu yang saya lihat tetapi saya tidak melihat alasan mengapa itu tidak berhasil. Anda mungkin ingin menggunakan daftar yang diurutkan sehingga bertahan terhadap dupes.
Pendekatan yang lebih umum adalah tingkat pengguna tunggal misalnya sistem, admin, pengguna listrik, pengguna dll. Sistem dapat melakukan segalanya, admin sebagian besar hal dan seterusnya.
Jika Anda menetapkan nilai peran sebagai kekuatan dua, Anda bisa menyimpan peran sebagai int dan mendapatkan peran jika Anda benar-benar ingin menyimpannya dalam satu bidang tetapi itu mungkin tidak sesuai selera semua orang.
Jadi, Anda mungkin memiliki:
Jadi jika pengguna memiliki nilai peran 6 maka mereka akan memiliki peran Front office dan Warehouse.
sumber
Gunakan HashSet karena mencegah duplikat dan memiliki lebih banyak metode perbandingan
Jika tidak, gunakan Enum dengan baik
Tambahkan metode Boolean IsInRole (Peran R)
dan saya akan melewatkan set
sumber
Contoh sederhana yang Anda berikan baik-baik saja, tetapi biasanya lebih rumit dari itu. Misalnya, jika Anda akan bertahan pengguna dan peran dalam database, maka Anda harus mendefinisikan peran dalam tabel database daripada menggunakan enum. Itu memberi Anda integritas referensial.
sumber
Jika suatu sistem - mungkin itu perangkat lunak, sistem operasi atau organisasi - berurusan dengan peran dan izin, akan tiba saatnya berguna untuk menambahkan peran dan mengelola izin untuknya.
Jika ini dapat diarsipkan dengan mengubah kode sumber, mungkin ok, untuk tetap menggunakan enum. Tetapi pada titik tertentu pengguna sistem ingin dapat mengelola peran dan izin. Dari enum menjadi tidak dapat digunakan.
Sebagai gantinya Anda akan ingin memiliki struktur data yang dapat dikonfigurasi. yaitu kelas UserRole yang juga memegang set izin yang ditugaskan untuk peran tersebut.
Kelas pengguna akan memiliki seperangkat peran. Jika ada kebutuhan untuk memeriksa izin pengguna, sekumpulan izin peran semua dibuat dan diperiksa jika itu berisi izin yang dipermasalahkan.
sumber