الميراث وتعدد الأشكال - سهولة الاستخدام مقابل نقاء

StackOverflow https://stackoverflow.com/questions/11854

سؤال

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

الحل الوحيد الذي يمكنني أن أفكر في أن يكون عضوا في الطبقة العودة السليم نوع الكائن عندما ضمنا مسبوك بدلا من الاعتماد على الميراث.سيكون من الأفضل أن تتخلى عن هو / لديه مثالية في مقابل سهولة البرمجة ؟

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

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

المحلول

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

class Damage {
    virtual void addDamage(int d) = 0;
    virtual int getDamage() = 0;
};

class Person : public virtual Damage {
    void addDamage(int d) {
        // ...
        damage += d * 2;
    }

    int getDamage() {
        return damage;
    }
};

class Car : public virtual Damage {
    void addDamage(int d) {
        // ...
        damage += d;
    }

    int getDamage() {
        return damage;
    }
};

الآن كل شخص و سيارة 'هو' الضرر, بمعنى أنها تنفذ الضرر واجهة.استخدام نقية فصول افتراضية (بحيث تكون مثل واجهات) هو مفتاح ينبغي أن تستخدم في كثير من الأحيان.فإنه يعزل التغيرات المستقبلية من تغيير النظام بأكمله.قراءة مفتوحة-مغلقة مبدأ للحصول على مزيد من المعلومات.

نصائح أخرى

أعتقد أنه يجب أن يكون تنفيذ واجهات أن تكون قادرة على فرض الخاصة بك لديه العلاقات (أنا أفعل هذا في C#):

public interface IDamageable
{
    void AddDamage(int i);
    int DamageCount {get;}
}

هل يمكن تطبيق هذا في الأشياء الخاصة بك:

public class Person : IDamageable

public class House : IDamageable

و سوف تكون على يقين من أن DamageCount الملكية ولها طريقة تسمح لك لإضافة الضرر ، دون أن يعني ذلك أن الشخص ومنزل ترتبط مع بعضها البعض في نوع من heirarchy.

أنا أتفق مع جون ، ولكن على افتراض كنت لا تزال بحاجة منفصلة الضرر عداد الطبقة ، يمكنك القيام به:

class IDamageable {
  virtual DamageCounter* damage_counter() = 0;
};
class DamageCounter {
  ...
};

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

class Damageable {
 public:
  DamageCounter damage_counter() { return damage_counter_; }
 private:
  DamageCounter damage_counter_;
};

ولكن الكثير من الناس لا بارد مع العديد من الميراث عند العديد من الآباء الأعضاء المتغيرات.

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

خيار واحد هو أن يكون هذه الكائنات تنفيذ Damageable واجهة بدلا من وراثة من DamageCounter.هذا شخص لديه الضرر العداد ، ولكن هو التلف.(غالبا ما أجد واجهات تجعل الكثير من معانيها كما صفة من الأسماء.) ثم هل يمكن أن يكون ثابت الضرر واجهة على Damageable الأشياء, و لا تعرض أن الضرر العداد تنفيذ الأساسية (إلا إذا كنت بحاجة إلى).

إذا كنت تريد أن تذهب القالب الطريق (على افتراض C++ أو ما شابه ذلك), هل يمكن أن تفعل هذا مع mixins ، ولكن يمكن الحصول على القبيح حقا بسرعة إذا فعل سيئة.

هذا السؤال محير فعلا :/

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

مجموعات من البيانات التي ينبغي معالجتها بطريقة مماثلة

ما هي الطريقة ؟ هي مجموعات معالجتها من خلال وظيفة ؟ آخر الصف ؟ عن طريق دالة ظاهري على البيانات ؟

ولا سيما كائنات مختلفة ومن فعل نفسه ، الذي سيكون في غاية يتحقق بسهولة مع تعدد الأشكال

المثالي "بالنيابة نفس" و تعدد الأشكال هي لا علاقة لها على الاطلاق.كيف تعدد الأشكال تجعل من السهل تحقيقه ؟

@كيفن

عادة عندما نتحدث عن 'هو' مقابل 'له' نحن نتحدث عن الميراث مقابل التكوين.

اممم الضرر العداد سيكون سمة واحدة من الفئات المشتقة و لن تناقش في شروط 'الشخص هو الضرر مكافحة' فيما يخص سؤالك.

وجود الضرر مكافحة كسمة لا تسمح له أن تنوع الكائنات مع تلف العدادات في المجموعة.على سبيل المثال, شخص و سيارة قد كلاهما تلف العدادات ، ولكن لا يمكن أن يكون vector<Person|Car> أو vector<with::getDamage()> أو أي شيء مماثل في معظم اللغات.إذا كان لديك كائن شائعة الفئة الأساسية, ثم يمكنك أن يشق لهم في هذا الطريق ، ولكن إذا كنت لا يمكن الوصول إلى getDamage() الطريقة بشكل عام.

هذا هو جوهر السؤال ، كما قرأت."يجب أن لا تنتهك is-a و has-a أجل علاج بعض الأشياء كما لو أنها هي نفسها ، على الرغم من أنهم ليسوا كذلك؟"

عادة عندما نتحدث عن 'هو' مقابل 'له' نحن نتحدث عن الميراث مقابل التكوين.

اممم الضرر العداد سيكون سمة واحدة من الفئات المشتقة و لن تناقش في شروط 'الشخص هو الضرر مكافحة' فيما يخص سؤالك.

انظر في هذا:

http://www.artima.com/designtechniques/compoinh.html

والتي قد تساعدك على طول الطريق.

@ديريك:من صياغة افترضت هناك كان قاعدة clase ، بعد إعادة قراءة السؤال أنا نوعا ما نرى الآن ما يريد الوصول إليه.

"الحق في القيام بذلك" سيكون لها فوائد على المدى الطويل ، إلا إذا كان بسبب شخص الحفاظ على النظام في وقت لاحق سوف تجد أنه من الأسهل أن نفهم إذا كان الحق في القيام به لتبدأ.

اعتمادا على اللغة ، قد يكون خيار متعددة الميراث ، ولكن عادة بسيطة واجهات يجعل معظم معانيها."بسيط" أعني جعل واجهة التي لا تحاول أن تكون أكثر من اللازم.من الأفضل أن يكون لديك الكثير من واجهات بسيطة و قليلة متجانسة منها.بالطبع هناك دائما مقايضة و الكثير من واجهات ربما تؤدي إلى تلك "المنسية" حول...

@أندرو

المثالي "بالنيابة نفس" و تعدد الأشكال هي لا علاقة لها على الاطلاق.كيف تعدد الأشكال تجعل من السهل تحقيقه ؟

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

foreach (obj in mylist)
    obj.addDamage(1)

ثم كنت بحاجة إلى أي لغة ديناميكية ، أو كنت في حاجة إليها تمتد من الفئة الأصل مشتركة (أو واجهة).على سبيل المثال:

class Person : DamageCounter {}
class Car : DamageCounter {}

foreach (DamageCounter d in mylist)
    d.addDamage(1)

ثم يمكنك علاج Person و Car نفس في بعض مفيدة جدا الظروف.

تعدد الأشكال لا تتطلب الميراث.تعدد الأشكال هو ما تحصل عليه عندما كائنات متعددة في تنفيذ نفس الرسالة التوقيع (الأسلوب).

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