سؤال

أجريت مناقشة في العمل بشأن "الميراث في نموذج المجال يعقد حياة المطورين". أنا مبرمج OO ، لذا بدأت أبحث عن الحجج التي أن وجود الميراث في نموذج المجال سوف يخفف حياة المطور فعليًا بدلاً من وجود مفاتيح في كل مكان.

ما أود رؤيته هو:

class Animal {

}

class Cat : Animal {

}

class Dog : Animal {

}

ما يقوله الزميل الآخر هو:

public enum AnimalType {
    Unknown,
    Cat,
    Dog
}

public class Animal {

    public AnimalType Type { get; set; }

}

كيف أقنعه (الروابط أهلا بك ) أن التسلسل الهرمي للصف سيكون أفضل من امتلاك خاصية التعداد لهذا النوع من المواقف؟

شكرًا!

هل كانت مفيدة؟

المحلول

إليكم كيف أسبب ذلك:

استخدم الميراث فقط إذا كان الدور/النوع لن يتغير أبدًا. على سبيل المثال

باستخدام الميراث لأشياء مثل:

رجل الإطفاء <- الموظف <- الشخص خطأ.

بمجرد أن يغير Freddy The Fireman الوظيفة أو يصبح عاطلاً عن العمل ، عليك قتله وإعادة إنشاء كائن جديد من النوع الجديد مع جميع العلاقات القديمة المرتبطة به.

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

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

على سبيل المثال

freddy.Roles.Add(new Employement( employmentDate, jobTitle ));

أو إذا كان ذلك مبالغة:

freddy.CurrentEmployment = new Employement( employmentDate, jobTitle );

وبهذه الطريقة ، يمكن أن يصبح فريدي مطورًا مع نضطر إلى قتله أولاً.

ومع ذلك ، لا يزال كل ما عندي من التراجع لم يتم الرد عليه إذا كان عليك استخدام التعداد أو التسلسل الهرمي لتوصيل الجبالة.

في Pure in Mem oo ، أقول إنه من الصواب استخدام الميراث لتوترات الوظائف هنا.

ولكن إذا كنت تقوم بتخطيط O/R ، فقد ينتهي بك الأمر بنموذج بيانات OverComplex خلف الكواليس إذا حاول Mapper تعيين كل نوع فرعي إلى جدول جديد. لذلك في مثل هذه الحالات ، غالبًا ما أذهب إلى نهج التعداد إذا لم يكن هناك سلوك حقيقي/معقد مرتبط بالأنواع. يمكنني العيش مع "if type == jobtitles.fireman ..." إذا كان الاستخدام محدودًا ويجعل الأمور أكثر تعقيدًا أو أقل تعقيدًا.

على سبيل المثال ، يمكن لمصمم Entity Framework 4 لـ .NET فقط تعيين كل نوع فرعي إلى جدول جديد. وقد تحصل على نموذج قبيح أو الكثير من الوصلات عند الاستعلام عن قاعدة البيانات الخاصة بك مع أي فائدة حقيقية.

ومع ذلك ، فأنا أستخدم الميراث إذا كان النوع/الدور ثابتًا. على سبيل المثال للمنتجات.

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

باختصار ، يعتمد ذلك ؛-)

أيضًا ، في نهاية اليوم ، من المحتمل أن ينتهي بك الأمر مع الكثير من عبارات التبديل في كلتا الحالتين. لنفترض أنك تريد تحرير "منتج" ، حتى لو كنت تستخدم الميراث ، فمن المحتمل أن يكون لديك رمز مثل هذا:

إذا كان (المنتج هو) استجابة.

لأن ترميز عنوان URL للكتاب في فئة الكيان سيكون قبيحًا لأنه سيجبر عملك على معرفة بنية موقعك وما إلى ذلك.

نصائح أخرى

التعدادات جيدة عندما:

  1. مجموعة القيم ثابتة ولا تتغير أبدًا أو نادرًا ما تتغير.
  2. تريد أن تكون قادرًا على تمثيل اتحاد القيم (أي الجمع بين الأعلام).
  3. لا تحتاج إلى إرفاق حالة أخرى بكل قيمة. (جافا ليس لديها هذا القيد.)

إذا تمكنت من حل مشكلتك برقم ، فمن المحتمل أن يكون التعداد مناسبًا وأكثر أمانًا. إذا كنت بحاجة إلى أي مرونة أكثر من ما سبق ، فمن المحتمل أن تكون التعدادات ليس الجواب الصحيح. باستخدام الفصول المتعددة الأشكال ، يمكنك:

  1. تأكد بشكل ثابت من معالجة جميع السلوك الخاص بالأنواع. على سبيل المثال ، إذا كنت بحاجة إلى جميع الحيوانات لتتمكن من ذلك Bark(), ، صناعة Animal دروس مع ملخص Bark() ستسمح الطريقة للمترجم بالتحقق من أن كل فئة فرعية تنفذها. إذا كنت تستخدم التعداد وكبير switch, ، لن يضمن أنك تعاملت مع كل حالة.

  2. يمكنك إضافة حالات جديدة (أنواع الحيوانات في مثالك). يمكن القيام بذلك عبر ملفات المصدر ، وحتى عبر حدود الحزمة. مع التعداد ، بمجرد إعلان ذلك ، يتم تجميدها. التمديد المفتوح هو واحد من نقاط القوة الأساسية لـ OOP.

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

public abstract class AnimalType {
    public static AnimalType Unknown { get; private set; }
    public static AnimalType Cat { get; private set; }
    public static AnimalType Dog { get; private set; }

    static AnimalType() {
        Unknown = new AnimalType("Unknown");
        Cat = new AnimalType("Cat");
        Dog = new AnimalType("Dog");
    }
}

public class Animal {
    public AnimalType Type { get; set; }
}

هذا يمنحك راحة التعداد: يمكنك القيام به AnimalType.Cat ويمكنك الحصول على نوع الحيوان. لكنه يمنحك أيضًا مرونة الفصول: يمكنك إضافة حقول إلى AnimalType لتخزين بيانات إضافية مع كل نوع ، إضافة طرق افتراضية ، وما إلى ذلك. الأهم من ذلك ، يمكنك تحديد أنواع الحيوانات الجديدة من خلال إنشاء مثيلات جديدة AnimalType.

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

وجود تعداد يشبه رمي حفلة لجميع هؤلاء Open/Closed Principle is for suckers اشخاص.

إنه يدعوك حقًا إلى التحقق مما إذا كان حيوانًا من نوع معين ثم تطبيق منطق مخصص لكل نوع. ويمكن أن يجعل ذلك رمزًا فظيعًا مما يجعل من الصعب الاستمرار في البناء على نظامك.

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

كلا الحللين على حق. يجب أن تبحث عن التقنيات التي تنطبق بشكل أفضل على المشكلة.

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

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

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