क्या सूची की सूची का उपयोग करना अच्छा है?


32

मैं वर्तमान में एक ऐसी प्रणाली पर काम कर रहा हूँ जहाँ उपयोगकर्ता हैं, और प्रत्येक उपयोगकर्ता की एक या एक से अधिक भूमिकाएँ हैं। क्या उपयोगकर्ता पर Enum मानों की सूची का उपयोग करना एक अच्छा अभ्यास है? मैं कुछ भी बेहतर नहीं सोच सकता, लेकिन यह ठीक नहीं लगता।

enum Role{
  Admin = 1,
  User = 2,
}

class User{
   ...
   List<Role> Roles {get;set;}
}

6
मुझे ठीक लगता है, मुझे इसके विपरीत किसी और की टिप्पणी देखने में दिलचस्पी होगी।
डेविड शोलेफील्ड

9
@MatthewRock एक व्यापक व्यापक सामान्यीकरण है। सूची <टी> .NET दुनिया में काफी आम है।
ग्राहम

7
@MatthewRock .NET सूची एक सरणी सूची है, जिसमें आपके द्वारा उल्लिखित एल्गोरिदम के समान गुण हैं।
im इतनी उलझन में

18
@MatthewRock - नहीं, आप लिंक्ड सूचियों के बारे में बात कर रहे हैं, जब प्रश्न, और बाकी सभी, सामान्य सूची इंटरफ़ेस के बारे में बात कर रहे हैं।
oद्रालो

5
ऑटो गुण C # की एक विशिष्ट विशेषता है (प्राप्त; सेट; वाक्यविन्यास)। इसके अलावा सूची वर्ग का नामकरण।

जवाबों:


37

टीएल; डीआर: आमतौर पर एनमों के संग्रह का उपयोग करना एक बुरा विचार है क्योंकि यह अक्सर खराब डिजाइन की ओर जाता है। एनमों का एक संग्रह आमतौर पर विशिष्ट तर्क के साथ अलग-अलग सिस्टम संस्थाओं के लिए कहता है।

एनम के कुछ उपयोग मामलों के बीच अंतर करना आवश्यक है। यह सूची केवल मेरे सिर के ऊपर है इसलिए और भी मामले हो सकते हैं ...

उदाहरण सभी सी # में हैं, मुझे लगता है कि आपकी पसंद की भाषा में समान निर्माण होंगे या आपके लिए उन्हें स्वयं लागू करना संभव होगा।

1. केवल एकल मान मान्य है

इस स्थिति में, मान अनन्य हैं, जैसे

public enum WorkStates
{
    Init,
    Pending,
    Done
}

यह कुछ काम है कि दोनों के लिए अमान्य है Pendingऔर Done। इसलिए इनमें से केवल एक मान मान्य है। यह एनम का एक अच्छा उपयोग-मामला है।

2. मूल्यों का संयोजन वैध है
इस मामले को झंडे भी कहा जाता है, C # [Flags]इन के साथ काम करने के लिए enum विशेषता प्रदान करता है । इस विचार को एक enum सदस्य के अनुरूप प्रत्येक के साथ bools या bits के सेट के रूप में तैयार किया जा सकता है । प्रत्येक सदस्य के पास दो की शक्ति का मूल्य होना चाहिए। बिटवाइज़ ऑपरेटरों का उपयोग करके संयोजन बनाए जा सकते हैं:

[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
}

Enum सदस्यों के संग्रह का उपयोग करना इस तरह के मामले में एक ओवरकिल है क्योंकि प्रत्येक enum सदस्य केवल एक बिट का प्रतिनिधित्व करता है जो या तो सेट है या परेशान है। मुझे लगता है कि अधिकांश भाषाएं इस तरह से निर्माण का समर्थन करती हैं। अन्यथा आप एक बना सकते हैं (जैसे इसका उपयोग करें bool[]और इसे संबोधित करें (1 << (int)YourEnum.SomeMember) - 1)।

a) सभी संयोजन मान्य हैं

हालांकि ये कुछ सरल मामलों में ठीक हैं, वस्तुओं का एक संग्रह अधिक उपयुक्त हो सकता है क्योंकि आपको अक्सर प्रकार के आधार पर अतिरिक्त जानकारी या व्यवहार की आवश्यकता होती है।

[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);
    }
}

(ध्यान दें: यह मानता है कि आप वास्तव में केवल आइसक्रीम के स्वाद के बारे में परवाह करते हैं - कि आपको स्कूप और शंकु के संग्रह के रूप में आइसक्रीम को मॉडल करने की आवश्यकता नहीं है)

बी) मूल्यों के कुछ संयोजन वैध हैं और कुछ नहीं

यह एक लगातार परिदृश्य है। मामला अक्सर यह हो सकता है कि आप दो अलग-अलग चीजों को एक एनम में डाल रहे हैं। उदाहरण:

[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; }
}

अब जबकि यह दोनों के लिए पूरी तरह से वैध है Vehicleऔर Buildingकरने के लिए Doorहै और Windowरों, है ना बहुत सामान्य के लिए है Buildingरों है करने के लिए Wheelहै।

इस मामले में, किसी भी मामले # 1 या # 2a को प्राप्त करने के लिए एनम को भागों में तोड़ना और / या वस्तु पदानुक्रम को संशोधित करना बेहतर होगा।

रचना विवेचन

किसी तरह, एनओएम ओओ में ड्राइविंग तत्व नहीं होते हैं क्योंकि एक इकाई के प्रकार को उस जानकारी के समान माना जा सकता है जो आमतौर पर एक एनम द्वारा प्रदान की जाती है।

उदाहरण के लिए IceCream# 2 से नमूना लें , IceCreamझंडे के बजाय इकाई में Scoopवस्तुओं का संग्रह होगा ।

Scoopएक Flavorसंपत्ति के लिए कम शुद्धतावादी दृष्टिकोण होगा । शुद्धतावादी दृष्टिकोण के लिए होगा Scoopके लिए एक सार आधार वर्ग होने के लिए VanillaScoop, ChocolateScoop... कक्षाओं के बजाय।

लब्बोलुआब यह है कि:
1. वह सब कुछ नहीं है जो "एक प्रकार की चीज" है, उसे enum करने की आवश्यकता है
। 2. जब कुछ enum सदस्य कुछ परिदृश्य में एक वैध ध्वज नहीं है, तो enum को कई अलग-अलग Enums में विभाजित करने पर विचार करें।

अब आपके उदाहरण के लिए (थोड़ा बदला हुआ):

public enum Role
{
    User,
    Admin
}

public class User
{
    public List<Role> Roles { get; set; }
}

मुझे लगता है कि इस सटीक मामले को मॉडल के रूप में देखा जाना चाहिए (ध्यान दें: वास्तव में एक्स्टेंसिबल नहीं है!):

public class User
{
    public bool IsAdmin { get; set; }
}

दूसरे शब्दों में - यह निहित है, Userयह एक है User, अतिरिक्त जानकारी है कि क्या वह एक है Admin

आप कई भूमिकाएं कि अनन्य नहीं हैं करने के लिए मिलता है (उदाहरण के लिए Userहो सकता है Admin, Moderator, VIP, ... एक ही समय में), कि या तो झंडे Enum उपयोग करने के लिए एक अच्छा समय है या एक abtract आधार वर्ग या इंटरफ़ेस होगा।

Roleजिम्मेदारियों के बेहतर पृथक्करण की ओर ले जाने के लिए एक वर्ग का उपयोग करना जहां Roleयह तय करने की जिम्मेदारी हो सकती है कि क्या यह एक दिया गया कार्य कर सकता है।

एक पहेली के साथ आपको सभी भूमिकाओं के लिए एक जगह तर्क रखना होगा। जो OO के उद्देश्य को पराजित करता है और आपको अनिवार्य रूप से वापस लाता है।

कल्पना करें कि Moderatorअधिकारों का संपादन किया गया है और अधिकारों Adminको संपादित और हटाना दोनों है।

एनम दृष्टिकोण ( Permissionsभूमिकाओं और अनुमतियों को नहीं मिलाने के लिए कहा जाता है):

[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;
    }
}

क्लास एप्रोच (यह एकदम सही है, आदर्श रूप से, आप IActionएक विज़िटर पैटर्न में चाहते हैं, लेकिन यह पोस्ट पहले से बहुत बड़ी है ...):

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));
    }
}

एक एनुम का उपयोग एक स्वीकार्य दृष्टिकोण हो सकता है, हालांकि (उदाहरण के प्रदर्शन)। यहां निर्णय मॉडल प्रणाली की आवश्यकताओं पर निर्भर करता है।


3
मुझे नहीं लगता है कि [Flags]सभी संयोजन किसी भी प्रकार से अधिक मान्य हैं और इसका मतलब है कि उस प्रकार के सभी चार बिलियन मान मान्य हैं। इसका सीधा सा मतलब है कि उन्हें एक ही क्षेत्र में जोड़ा जा सकता है - संयोजन पर कोई भी प्रतिबंध उच्च-स्तरीय तर्क से संबंधित है।
रैंडम 832

चेतावनी: उपयोग करते समय [Flags], आपको मूल्यों को दो की शक्तियों पर सेट करना चाहिए, अन्यथा यह अपेक्षा के अनुरूप काम नहीं करेगा।
आर्टुरो टॉरेस सांचेज़

@ Random832 मेरा यह कहने का इरादा कभी नहीं था लेकिन मैंने जवाब को संपादित किया - आशा है कि यह अब स्पष्ट हो जाएगा।
जेडेनक जेनेक

1
@ ArturoTorresSánchez इनपुट के लिए धन्यवाद, मैंने जवाब तय कर लिया है और इसके बारे में एक व्याख्यात्मक नोट भी जोड़ा है।
जेडेनक जेनेक

महान व्याख्या! वास्तव में झंडे बहुत अच्छी तरह से सिस्टम आवश्यकताओं को फिट करते हैं, हालांकि मौजूदा सेवा कार्यान्वयन के कारण हैशसेट का उपयोग करना आसान होगा।
डेक्सी

79

सेट का उपयोग क्यों नहीं करें? यदि सूची का उपयोग किया जा रहा है:

  1. एक ही भूमिका को दो बार जोड़ना आसान है
  2. सूचियों की नई तुलना यहां ठीक से काम नहीं करेगी: [उपयोगकर्ता, व्यवस्थापक] [व्यवस्थापक, उपयोगकर्ता] के समान नहीं है
  3. जटिल ऑपरेशन जैसे कि प्रतिच्छेदन और मर्ज लागू करने के लिए सीधे नहीं हैं

यदि आप प्रदर्शन के बारे में चिंतित हैं, तो, उदाहरण के लिए, जावा में, EnumSetबूलियन्स की निश्चित लंबाई सरणी के रूप में कार्यान्वित किया जाता है (i'th बूलियन तत्व इस प्रश्न का उत्तर देता है कि क्या इस सेट में आई एनम मूल्य मौजूद है या नहीं)। उदाहरण के लिए, EnumSet<Role>। यह भी देखें EnumMap। मुझे शक है कि C # में भी कुछ ऐसा ही है।


35
वास्तव में जावा EnumSetएस को बिट फील्ड के रूप में लागू किया जाता है।
biziclop

4
सम्बंधित SO प्रश्न HashSet<MyEnum>बनाम फ्लैग
एनमों

3
.NET में है FlagsAttribute, जो आपको बिटकॉइन ऑपरेटर्स को एनामेट को समाप्‍त करने की सुविधा देता है। जावा के समान लगता है EnumSetmsdn.microsoft.com/en-US/LIBRARY/system.flagsattribute EDIT: मुझे एक उत्तर देना चाहिए था! इसका एक अच्छा उदाहरण है।
Ps2goat

4

अपनी Enum लिखें ताकि आप उन्हें जोड़ सकें। बेस 2 घातांक का उपयोग करके आप उन सभी को एक एनम में जोड़ सकते हैं, 1 संपत्ति है और उनके लिए जांच कर सकते हैं। आपकी एनम को यह चाटना चाहिए

enum MyEnum
{ 
    FIRST_CHOICE = 2,
    SECOND_CHOICE = 4,
    THIRD_CHOICE = 8
}

3
किसी भी कारण से आप 1 का उपयोग क्यों नहीं कर रहे हैं?
रोबी डे

1
@ रॉबीडीई कोई प्रभावकारी रूप से मैं 1, 2, 4, 8, आदि का उपयोग नहीं कर सकता था
रेमी

5
यदि आप जावा का उपयोग करते हैं, तो यह पहले से ही एस के EnumSetलिए लागू करता है enum। आपके पास पहले से ही अमूर्त, सभी बूलियन अंकगणित हैं, साथ ही कुछ अन्य तरीकों का उपयोग करना आसान है, साथ ही छोटी मेमोरी और अच्छा प्रदर्शन।
14:13 बजे fr13d

2
@ fr13d मैं एसी # आदमी हूं और चूंकि सवाल का कोई जावा टैग नहीं है, मुझे लगता है कि यह जवाब बड़े पैमाने पर अधिक लागू होता है
रेमी

1
सही है, @ रेमी। C # वह [flags]विशेषता प्रदान करता है , जो @ Zdeněk Jelínek अपने पोस्ट में खोज करता है ।
15:13 बजे fr13d

4

क्या उपयोगकर्ता पर Enum मानों की सूची का उपयोग करना एक अच्छा अभ्यास है?


संक्षिप्त उत्तर : हां


बेहतर संक्षिप्त उत्तर : हाँ, एनम डोमेन में कुछ परिभाषित करता है।


डिज़ाइन-टाइम उत्तर : डोमेन के रूप में डोमेन को मॉडल करने वाली कक्षाओं, संरचनाओं आदि को बनाएं और उनका उपयोग करें।


कोडिंग समय का उत्तर : यहां कोड-स्लिंग एनमों के बारे में बताया गया है ...


अनुमान सवाल :

  • क्या मुझे स्ट्रिंग्स का उपयोग करना चाहिए?

    • उत्तर: नहीं।
  • क्या मुझे किसी अन्य वर्ग का उपयोग करना चाहिए?

    • इसके अलावा, हाँ। इसके बजाय, नहीं।
  • क्या Roleएनम सूची में उपयोग के लिए पर्याप्त है User?

    • मुझे पता नहीं है। यह सबूत में नहीं अन्य डिजाइन विवरणों पर अत्यधिक निर्भर है।

डब्ल्यूटीएफ बॉब?

  • यह एक डिजाइन प्रश्न है जिसे प्रोग्रामिंग लैंग्वेज तकनीकी में फंसाया गया है।

    • एक enumएक अच्छा तरीका है अपने मॉडल में "भूमिकाओं" को परिभाषित करने के लिए है। तो फिर Listभूमिकाओं की एक अच्छी बात है।
  • enum तार से बेहतर है।

    • Role डोमेन में मौजूद सभी भूमिकाओं की घोषणा है।
    • स्ट्रिंग "एडमिन" "A" "d" "m" "i" "n"उस क्रम में अक्षरों के साथ एक स्ट्रिंग है । जहाँ तक डोमेन का सवाल है यह कुछ भी नहीं है।
  • कोई भी वर्ग जिसे आप Roleकुछ जीवन की अवधारणा देने के लिए डिज़ाइन कर सकते हैं - कार्यक्षमता - Roleएनम का अच्छा उपयोग कर सकते हैं ।

    • हर तरह की भूमिका के लिए उप-वर्ग के बजाय उदाहरण के लिए, एक Roleसंपत्ति है जो बताती है कि यह वर्ग-उदाहरण किस तरह की भूमिका है।
    • User.Rolesजब हमें आवश्यकता नहीं होती है या नहीं चाहते हैं, तो एक सूची उचित होती है, तात्कालिक भूमिका ऑब्जेक्ट।
    • और जब हमें किसी भूमिका को तुरंत करने की आवश्यकता होती है, तो एनम एक गैर-अस्पष्ट, एक RoleFactoryवर्ग के लिए संवाद करने का सुरक्षित तरीका है ; और, कोड पाठक के लिए, महत्वहीन रूप से नहीं।

3

यह कुछ ऐसा नहीं है जो मैंने देखा है, लेकिन मुझे कोई कारण नहीं दिखता कि यह काम क्यों नहीं करेगा। आप क्रमबद्ध सूची का उपयोग करना चाह सकते हैं, लेकिन यह हालांकि डूप के खिलाफ बचाव करता है।

एक अधिक सामान्य दृष्टिकोण एक एकल उपयोगकर्ता स्तर है जैसे सिस्टम, व्यवस्थापक, पावर उपयोगकर्ता, उपयोगकर्ता आदि। सिस्टम सब कुछ कर सकता है, अधिकांश चीजों को प्रशासित कर सकता है और इसी तरह नीचे।

यदि आप दो की शक्तियों के रूप में भूमिकाओं के मूल्यों को निर्धारित करते हैं, तो आप भूमिका को एक इंट के रूप में संग्रहीत कर सकते हैं और भूमिकाओं को प्राप्त कर सकते हैं यदि आप वास्तव में उन्हें एक ही क्षेत्र में संग्रहीत करना चाहते हैं, लेकिन यह हर किसी के स्वाद के लिए नहीं हो सकता है।

तो आपके पास हो सकता है:

Back office role 1
Front office role 2
Warehouse role 4
Systems role 8

इसलिए यदि किसी उपयोगकर्ता की भूमिका मूल्य 6 थी, तो उनके सामने फ्रंट ऑफिस और वेयरहाउस भूमिकाएं होंगी।


2

HashSet का उपयोग करें क्योंकि यह डुप्लिकेट को रोकता है और इसमें तुलनात्मक तरीके अधिक हैं

अन्यथा एनम का अच्छा उपयोग

एक विधि जोड़ें बूलियन IsInRole (भूमिका आर)

और मैं सेट छोड़ देता

List<Role> roles = new List<Role>();
Public List<Role> Roles { get {return roles;} }

1

आपके द्वारा दिया गया सरल उदाहरण ठीक है, लेकिन आमतौर पर यह उससे अधिक जटिल है। उदाहरण के लिए, यदि आप किसी डेटाबेस में उपयोगकर्ताओं और भूमिकाओं को बनाए रखने जा रहे हैं, तो आपको एक डेटाबेस तालिका के बजाय भूमिकाओं को परिभाषित करना चाहिए। यह आपको संदर्भात्मक अखंडता प्रदान करता है।


0

यदि एक प्रणाली - यह एक सॉफ्टवेयर, एक ऑपरेशन सिस्टम या एक संगठन हो सकता है - भूमिकाओं और अनुमति से संबंधित है, एक समय आता है जब यह भूमिकाएं जोड़ने और उनके लिए अनुमतियों को प्रबंधित करने के लिए उपयोगी होता है।
यदि यह स्रोत कोड को बदलकर संग्रहीत किया जा सकता है, तो यह ठीक हो सकता है, Enums के साथ छड़ी करने के लिए। लेकिन कुछ बिंदु पर सिस्टम का उपयोगकर्ता भूमिकाओं और अनुमतियों का प्रबंधन करने में सक्षम होना चाहता है। थान एनम अनुपयोगी हो जाते हैं।
इसके बजाय आप एक विन्यास योग्य डेटा संरचना रखना चाहेंगे। यानी एक UserRole वर्ग जो भूमिका के लिए सौंपी गई अनुमति का एक सेट रखता है।
एक उपयोगकर्ता वर्ग में भूमिकाओं का एक सेट होगा। यदि उपयोगकर्ता की अनुमति की जांच करने की आवश्यकता है, तो सभी भूमिकाओं की अनुमतियों का एक संघ सेट बनाया जाता है और जांच की जाती है कि क्या इसमें प्रश्न शामिल है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.