سؤال

ما هو تصميم الفصل الأفضل ولماذا؟

public class User
{
    public String UserName;
    public String Password;
    public String FirstName;
    public String LastName;
}

public class Employee : User
{
    public String EmployeeId;
    public String EmployeeCode;
    public String DepartmentId;
}

public class Member : User
{
    public String MemberId;
    public String JoinDate;
    public String ExpiryDate;
}

أو

public class User
{
    public String UserId;
    public String UserName;
    public String Password;
    public String FirstName;
    public String LastName;
}

public class Employee
{
    public User UserInfo;
    public String EmployeeId;
    public String EmployeeCode;
    public String DepartmentId;
}

public class Member
{
    public User UserInfo;
    public String MemberId;
    public String JoinDate;
    public String ExpiryDate;
}
هل كانت مفيدة؟

المحلول

تتم الإجابة على هذا السؤال ببساطة من خلال إدراك أن الميراث يمثل علاقة "IS-A"، في حين أن العضوية تمثل علاقة "HAS-A".

  • الموظف هو مستخدم
  • الموظف لديه معلومات المستخدم

أيهما صحيح؟هذه هي إجابتك.

نصائح أخرى

أنا لا أحب أي منهما.ماذا يحدث عندما يكون شخص ما عضوًا وموظفًا؟

اسأل نفسك ما يلي:

  • هل ترغب في نموذج الموظف يكون مستخدم؟إذا كان الأمر كذلك، اختار الميراث.
  • هل ترغب في نموذج الموظف لديه معلومات المستخدم؟إذا كان الأمر كذلك، استخدم التكوين.
  • هل يتم تضمين الوظائف الافتراضية بين المستخدم (المعلومات) والموظف؟إذا كان الأمر كذلك، استخدم الميراث.
  • هل يمكن للموظف أن يكون لديه مثيلات متعددة للمستخدم (المعلومات)؟إذا كان الأمر كذلك، استخدم التكوين.
  • هل يعقل تعيين كائن موظف لكائن مستخدم (معلومات)؟إذا كان الأمر كذلك، استخدم الميراث.

بشكل عام، احرص على تصميم نموذج للواقع الذي يحاكيه برنامجك، في ظل قيود تعقيد التعليمات البرمجية والكفاءة المطلوبة.

لا أعتقد أن التكوين دائمًا أفضل من الميراث (عادةً فقط).إذا كان الموظف والعضو مستخدمين حقًا، وهما متنافيان، فإن التصميم الأول هو الأفضل.ضع في اعتبارك السيناريو الذي تحتاج فيه إلى الوصول إلى اسم المستخدم الخاص بالموظف.باستخدام التصميم الثاني سيكون لديك:

myEmployee.UserInfo.UserName

وهو أمر سيء (قانون ديميتر)، لذلك عليك إعادة البناء على:

myEmployee.UserName

الأمر الذي يتطلب طريقة صغيرة على الموظف لتفويض كائن المستخدم.يتم تجنب كل ذلك من خلال التصميم الأول.

سؤال جميل على الرغم من تجنب الانحرافات عنه يمين و خطأ سأفكر في السؤال عن إيجابيات وسلبيات كل نهج - أعتقد أن هذا ما قصدته بما هو الأفضل أو الأسوأ ولماذا.على أي حال ....

النهج الأول ويعرف أيضا باسم الميراث

الايجابيات:

  • يسمح بسلوك متعدد الأشكال.
  • يكون بدءًا بسيطة ومريحة.

سلبيات:

  • يمكن تصبح معقدة أو خرقاء مع مرور الوقت لو يتم إضافة المزيد من السلوك والعلاقات.

النهج الثاني ويعرف أيضا باسم التكوين

الايجابيات:

  • يرسم خرائط جيدة للسيناريوهات التي لا تتضمن OOP مثل الجداول العلائقية والبرمجة المنظمة وما إلى ذلك
  • من السهل (إن لم يكن مناسبًا بالضرورة) القيام بذلك تدريجيا توسيع العلاقات والسلوك.

سلبيات:

  • لا يوجد تعدد الأشكال، لذلك يكون استخدام المعلومات والسلوكيات ذات الصلة أقل ملاءمة

قوائم مثل هذه + الأسئلة جون ليمجاب المذكورة سوف تساعدك على اتخاذ القرارات والبدء - وبعد ذلك يمكنك العثور على ما يمين كان من المفترض أن تكون الإجابات ;-)

يمكنك أيضًا التفكير في الموظف باعتباره دور للمستخدم (الشخص).يمكن أن يتغير دور المستخدم بمرور الوقت (يمكن أن يصبح المستخدم عاطلاً عن العمل) أو يمكن أن يكون للمستخدم أدوار متعددة في نفس الوقت.

الميراث أفضل بكثير عندما يكون هناك حقيقي علاقة "هي" على سبيل المثال Apple - Fruit.لكن كن حذرًا جدًا:الدائرة - الشكل الناقص ليس علاقة حقيقية، لأن الدائرة تتمتع "بحرية" أقل من الشكل الناقص (الدائرة عبارة عن علاقة ولاية القطع الناقص) - انظر: مشكلة الدائرة البيضوية.

الأسئلة الحقيقية هي:

  • ما هي قواعد العمل وقصص المستخدم وراء المستخدم؟
  • ما هي قواعد العمل وقصص المستخدم وراء الموظف؟
  • ما هي قواعد العمل وقصص المستخدم وراء العضو؟

يمكن أن تكون هذه ثلاثة كيانات غير مرتبطة تمامًا أم لا، وهذا سيحدد ما إذا كان تصميمك الأول أو الثاني سيعمل، أو ما إذا كان هناك تصميم آخر مختلف تمامًا.

لا أحد جيد.حالة قابلة للتغيير أكثر من اللازم.يجب ألا تكون قادرًا على إنشاء مثيل لفئة في حالة غير صالحة أو تمت تهيئتها جزئيًا.

ومع ذلك فالثاني أفضل لأنه يفضل المركب على الميراث.

قد يساعد ذكر متطلباتك/مواصفاتك في الوصول إلى "أفضل تصميم".
سؤالك هو أيضًا "تفسير خاضع للقارئ" في الوقت الحالي.

إليك السيناريو الذي يجب أن تفكر فيه:

يُفضل التركيب (المثال الثاني) إذا كان يمكن لنفس المستخدم أن يكون موظفًا وعضوًا.لماذا؟لأنه بالنسبة للمثيلين (الموظف والعضو) اللذين يمثلان نفس المستخدم، إذا تغيرت بيانات المستخدم، فلن يتعين عليك تحديثها في مكانين.يحتوي مثيل المستخدم فقط على جميع معلومات المستخدم، ويجب تحديثه فقط.نظرًا لأن فئتي الموظف والعضو تحتويان على نفس مثيل المستخدم، فسوف تحتويان تلقائيًا على المعلومات المحدثة.

ثلاثة خيارات أخرى:

  1. لديك User تحتوي الفئة على معلومات تكميلية لكل من الموظفين والأعضاء، مع وجود حقول غير مستخدمة فارغة (ملف ID من معين User سيشير إلى ما إذا كان المستخدم موظفًا أو عضوًا أو كليهما أو أيًا كان).

  2. أحصل على User فئة تحتوي على إشارة إلى ISupplementalInfo, ، أين ISupplementalInfo يرثها ISupplementalEmployeeInfo, ISupplementalMemberInfo, ، إلخ.الكود الذي ينطبق على جميع المستخدمين يمكن العمل معه User كائنات الفئة والرمز الذي يحتوي على User يمكن للمرجع الوصول إلى المعلومات التكميلية للمستخدم، ولكن هذا النهج من شأنه أن يتجنب الاضطرار إلى التغيير User إذا كانت هناك حاجة إلى مجموعات مختلفة من المعلومات التكميلية في المستقبل.

  3. كما هو مذكور أعلاه، ولكن لديك User فئة تحتوي على نوع من مجموعة من ISupplementalInfo.سيكون لهذا الأسلوب ميزة تسهيل إضافة الخصائص إلى المستخدم في وقت التشغيل (على سبيل المثال.لأن أ Member تم التعاقد).عند استخدام النهج السابق، يتعين على المرء تحديد فئات مختلفة لمجموعات مختلفة من الخصائص؛إن تحويل "عضو" إلى "عضو + عميل" يتطلب رمزًا مختلفًا عن تحويل "موظف" إلى "موظف + عميل".عيب النهج الأخير هو أنه سيجعل من الصعب الحماية من السمات الزائدة أو غير المتسقة (باستخدام شيء مثل Dictionary<Type, ISupplementalInfo> للاحتفاظ بمعلومات تكميلية يمكن أن يكون ناجحًا، ولكنه قد يبدو "ضخمًا" قليلاً).

وأنا أميل إلى تفضيل النهج الثاني، لأنه يسمح بالتوسع المستقبلي بشكل أفضل من الميراث المباشر.قد يكون العمل مع مجموعة من الكائنات بدلاً من كائن واحد مرهقًا بعض الشيء، ولكن هذا النهج قد يكون أكثر قدرة من الأساليب الأخرى على التعامل مع المتطلبات المتغيرة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top