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
public enum WorkStates
{
Init,
Pending,
Done
}
Tidak valid memiliki beberapa pekerjaan yang keduanya Pendingdan Done. 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 set bools atau bits dengan masing-masing sesuai dengan satu anggota enum. Setiap anggota harus memiliki nilai kekuatan dua. Kombinasi dapat dibuat menggunakan operator bitwise:
[Flags]
public enum Flags
{
None = 0,
Flag0 = 1, // 0x01, 1 << 0
Flag1 = 2, // 0x02, 1 << 1
Flag2 = 4, // 0x04, 1 << 2
Flag3 = 8, // 0x08, 1 << 3
Flag4 = 16, // 0x10, 1 << 4
AFrequentlyUsedMask = Flag1 | Flag2 | Flag4,
All = ~0 // bitwise negation of zero is all ones
}
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.
[Flags]
public enum Flavors
{
Strawberry = 1,
Vanilla = 2,
Chocolate = 4
}
public class IceCream
{
private Flavors _scoopFlavors;
public IceCream(Flavors scoopFlavors)
{
_scoopFlavors = scoopFlavors
}
public bool HasFlavor(Flavors flavor)
{
return _scoopFlavors.HasFlag(flavor);
}
}
(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:
[Flags]
public enum Parts
{
Wheel = 1,
Window = 2,
Door = 4,
}
public class Building
{
public Parts parts { get; set; }
}
public class Vehicle
{
public Parts parts { get; set; }
}
Sekarang walaupun benar-benar valid untuk keduanya Vehicledan Buildingmemiliki Doors dan Windows, tidak biasa bagi Buildings untuk memiliki Wheels.
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 IceCreamsampel dari # 2, IceCreamentitas bukannya bendera memiliki koleksi Scoopobjek.
Pendekatan yang kurang murni adalah untuk Scoopmemiliki Flavorproperti. Pendekatan murni akan untuk Scoopmenjadi kelas dasar abstrak untuk VanillaScoop, 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):
public enum Role
{
User,
Admin
}
public class User
{
public List<Role> Roles { get; set; }
}
Saya pikir case yang tepat ini harus dimodelkan sebagai (note: not really extensible!):
public class User
{
public bool IsAdmin { get; set; }
}
Dengan kata lain - itu adalah implisit, bahwa itu Useradalah User, info tambahan adalah apakah dia seorang Admin.
Jika Anda bisa memiliki peran ganda yang tidak eksklusif (misalnya Userbisa Admin, 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 Rolepetunjuk mengarah ke pemisahan tanggung jawab yang lebih baik di mana a Roledapat 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 Moderatormemiliki hak edit dan Adminmemiliki hak mengedit dan menghapus.
Pendekatan Enum (dipanggil Permissionsagar tidak mencampuradukkan peran dan izin):
[Flags]
public enum Permissions
{
None = 0
CanEdit = 1,
CanDelete = 2,
ModeratorPermissions = CanEdit,
AdminPermissions = ModeratorPermissions | CanDelete
}
public class User
{
private Permissions _permissions;
public bool CanExecute(IAction action)
{
if (action.Type == ActionType.Edit && _permissions.HasFlag(Permissions.CanEdit))
{
return true;
}
if (action.Type == ActionType.Delete && _permissions.HasFlag(Permissions.CanDelete))
{
return true;
}
return false;
}
}
Pendekatan kelas (ini jauh dari sempurna, idealnya, Anda menginginkan IActionpola pengunjung dalam tetapi postingan ini sudah sangat besar ...):
public interface IRole
{
bool CanExecute(IAction action);
}
public class ModeratorRole : IRole
{
public virtual bool CanExecute(IAction action)
{
return action.Type == ActionType.Edit;
}
}
public class AdminRole : ModeratorRole
{
public override bool CanExecute(IAction action)
{
return base.CanExecute(action) || action.Type == ActionType.Delete;
}
}
public class User
{
private List<IRole> _roles;
public bool CanExecute(IAction action)
{
_roles.Any(x => x.CanExecute(action));
}
}
Menggunakan enum mungkin merupakan pendekatan yang dapat diterima (misalnya kinerja). Keputusan di sini tergantung pada persyaratan sistem yang dimodelkan.