سؤال

هذا إلى حد ما سؤال متابعة لهذا سؤال.

لنفترض أن لدي شجرة الميراث على النحو التالي:

Car -> Ford -> Mustang -> MustangGT

هل هناك فائدة لتحديد واجهات لـ كل من هذه الفئات؟مثال:

ICar -> IFord -> IMustang -> IMustangGT

أستطيع أن أرى أنه ربما فئات أخرى (مثل Chevy) ترغب في التنفيذ Icar أو IFord وربما حتى IMustang, ولكن ربما لا IMustangGT لأنها محددة جدا.هل الواجهات زائدة عن الحاجة في هذه الحالة؟

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

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

المحلول

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

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

آدم

نصائح أخرى

أنا أيضا أتفق مع استجابة Adamalex يجب مشاركة الواجهات من قبل الفئات التي يجب أن تستجيب لطرق معينة.

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

بينما نستخدم تشبيه السيارة ، مثال ملموس. دعنا نقول أن لدينا الفصول التالية:

Car -> Ford   -> Escape  -> EscapeHybrid
Car -> Toyota -> Corolla -> CorollaHybrid

السيارات لها wheels ويمكن Drive() و Steer(). لذلك يجب أن توجد هذه الطرق في Car صف دراسي. (ربما Car سيكون الفصل فئة مجردة.)

النزول على الخط ، نحصل على التمييز بين Ford و Toyota (ربما يتم تنفيذها كاختلاف في نوع الشعار على السيارة ، وربما مرة أخرى على الأرجح فئة مجردة.)

ثم ، أخيرًا لدينا ملف Escape و Corolla الفصل الدراسي التي يتم تنفيذها بالكامل كسيارة.

الآن ، كيف يمكننا صنع ملف هجين عربة؟

يمكن أن يكون لدينا فئة فرعية من Escape هذا هو EscapeHybrid الذي يضيف أ FordsHybridDrive() الطريقة ، وفئة فرعية من Corolla هذا هو CorollaHybrid مع ToyotasHybridDrive() طريقة. تقوم الطرق بشكل أساسي بنفس الشيء ، ولكن لدينا طرق مختلفة. يوك. يبدو أننا نستطيع أن نفعل أفضل من ذلك.

دعنا نقول أن الهجين لديه HybridDrive() طريقة. نظرًا لأننا لا نريد أن ينتهي الأمر بوجود نوعين مختلفين من الهجينة (في عالم مثالي) ، حتى نتمكن من عمل IHybrid الواجهة التي لديها ملف HybridDrive() طريقة.

لذا، إذا كنا نريد عمل EscapeHybrid أو CorollaHybrid صف دراسي, ، كل ما علينا فعله هو تنفيذ IHybrid واجهه المستخدم.

للحصول على مثال في العالم الحقيقي ، دعونا نلقي نظرة على Java. فئة يمكنها القيام بمقارنة كائن مع كائن آخر ينفذ Comparable واجهه المستخدم. كما يوحي الاسم ، يجب أن تكون الواجهة لفئة مماثلة, ، وبالتالي اسم "مماثل".

مثلما يهم ، أ مثال السيارة يستخدم في واجهات درس تعليمي جافا.

يجب ألا تنفذ أي من هذه الواجهات على الإطلاق.

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

يجب أن تصف الواجهة يا له من كائن يفعل), ، أو ما يتصرف به. أعني بهذا السلوك ، ومجموعة العمليات المنطقية بالنظر إلى هذا السلوك.

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

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

آمل أن يساعدك ذلك في التفكير من خلال الواجهات التي يجب أن تحتاجها بالفعل :-)

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

لا تبني الأشياء التي لا تحتاجها. إذا اتضح أنك بحاجة إلى واجهات ، فهذا جهد صغير للعودة وبناءها.

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

قم بإنشائه فقط بمجرد أن يصبح هذا المستوى من الوظيفة ضروريًا.

رمز إعادة الانتهاء من التمثيل هو دائمًا في عملية مستمرة.

هناك أدوات متوفرة تتيح لك الاستخراج للواجهة إذا لزم الأمر. على سبيل المثال http://geekswithblogs.net/jaysmith/archive/2008/02/27/refactor-visual-studio-extract-interface.aspx

اصنع icar وجميع الباقي (اجعل = ford ، model = mustang ، والأشياء) كأعضاء في فئة تنفذ الواجهة.

قد ترغب في الحصول على فئة Ford الخاصة بك وعلى سبيل المثال فئة GM وتنفيذ ICAR من أجل استخدام تعدد الأشكال إذا كنت لا تريد أن تسير في طريق التحقق Make == Whatever, ، هذا متروك لأسلوبك.

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

هل يمكن لفورد أن تفعل الأشياء التي لا تستطيع السيارات الأخرى؟ أنا لا أعتقد ذلك.

سأقوم بإنشاء المستويين الأولين، ICar وIFord واترك المستوى الثاني بمفرده حتى أحتاج إلى واجهة في ذلك المستوى الثاني.

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

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

Ivehichle -> Carimpl ، MotorbikeImpl -HAS -A -A -A -Many ModelNames

في هذه الإجابة حول الفرق بين الواجهة والفئة, أوضحت ذلك:

  • تكشف الواجهة ما هو المفهوم هو (من حيث "ماذا هو"صالح ، في وقت التجميع) ، ويستخدم ل القيم (MyInterface X = ...)
  • يكشف الفصل ما هو المفهوم يفعل (تم تنفيذها فعليًا في وقت التشغيل) ، ويستخدم للقيم أو للكائنات (MyClass X أو Amyclass.method ())

لذلك إذا كنت بحاجة إلى تخزينها في متغير "فورد" (فكرة "القيمة") فئات فرعية مختلفة من فورد ، قم بإنشاء iford. خلاف ذلك ، لا تهتم حتى تحتاجها بالفعل.

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

في رأيي ، تعتبر واجهاتي أداة لفرض شرط أن يقوم الفصل بتنفيذ توقيع معين ، أو (كما أحب أن أفكر في الأمر) ضمير شخصي ، وأحاول تسمية واجهاتي حتى يمكن قراءتها بهذه الطريقة ... icanfly ، knowhowtopersistmyself iamdisplayable ، إلخ ... لذلك في مثالك ، لن أقوم بإنشاء واجهة لتعكس التوقيع العام الكامل لأي شخص محدد صف دراسي. أود تحليل التوقيع العام (السلوك) ثم فصل الأعضاء إلى مجموعات منطقية أصغر (أصغر أفضل) مثل (باستخدام مثالك) Imove ، iusefuel ، icarrypassengers ، لا يطاق ، iaccelerate ، exepreciate ، إلخ ... ثم تنطبق تلك الواجهات على أي فصول أخرى في نظامي تحتاج إليها

بشكل عام ، فإن أفضل طريقة للتفكير في هذا (والعديد من الأسئلة في OO) هي التفكير في فكرة العقد.

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

مع وضع ذلك في الاعتبار ، يعتمد سؤالك إلى حد ما على اللغة التي تستخدمها وما تريد القيام به.

بعد سنوات عديدة من القيام بـ OO (مثل ، يا إلهي ، 30 عامًا) ، كنت عادةً ما أكتب واجهة لكل عقد ، خاصة في Java ، لأنها تجعل الاختبارات أسهل بكثير: إذا كان لدي واجهة للفصل ، فيمكنني البناء أشياء وهمية بسهولة ، تقريبا تافهة.

تهدف الواجهات إلى أن تكون واجهة برمجة تطبيقات عامة عامة ، وسيقتصر المستخدمون على استخدام واجهة برمجة التطبيقات العامة هذه. ما لم تكن تنوي المستخدمين استخدام الأساليب الخاصة بـ IMustangGT, ، قد ترغب في الحد من التسلسل الهرمي للواجهة ICar و IExpensiveCar.

يرث فقط من الواجهات والفصول التجريدية.

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

إذا قمت بتطبيق فورد فورد والطريقة هي نفسها مثل موستانج ، فاشتر من موستانج:

class Ford{
  public function Foo(){
    ...
    Mustang mustang  = new Mustang();
    return mustang.Foo();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top