oop الفرق - متى تستخدم واجهة بدلاً من صف مجردة والعكس بالعكس؟




بين شرح (18)

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

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

متى يريد المرء استخدام واجهة ومتى يريد المرء استخدام فئة مجردة ؟



هذا يمكن أن يكون دعوة صعبة للغاية لجعل ...

مؤشر واحد يمكنني تقديمه: يمكن للعنصر تنفيذ العديد من الواجهات ، في حين أن كائن ما يمكن أن يرث طبقة أساسية واحدة فقط (بلغة OO الحديثة مثل c # ، أعرف أن C ++ لها ميراث متعدد - لكن أليس هذا مستاءً؟)


فئة مجردة يمكن أن يكون لها تطبيقات.

واجهة ليس لديها تطبيقات ، فهي ببساطة تحدد نوع العقد.

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


إذا كنت تنظر إلى جافا بلغة OOP ،

" الواجهة لا توفر تطبيق الطريقة " لم تعد صالحة مع إطلاق Java 8. الآن java يوفر التطبيق في واجهة للطرق الافتراضية.

بعبارات بسيطة ، أود أن استخدم

واجهة: لتنفيذ العقد من قبل كائنات متعددة غير ذات صلة. يوفر إمكانية " HAS A ".

الفئة التجريدية: لتنفيذ السلوك نفسه أو مختلف بين كائنات متعددة ذات صلة. إنها تنشئ علاقة " IS A ".

يوفر website Oracle الاختلافات الرئيسية بين interface abstract .

فكر في استخدام دروس الملخص إذا:

  1. تريد مشاركة التعليمات البرمجية بين عدة فئات وثيقة الصلة.
  2. تتوقع أن تحتوي الفئات التي تمدد فئة الملخص على العديد من الطرق أو الحقول الشائعة ، أو تتطلب معدِّلات وصول غير عامة (مثل المحمية والخاصة).
  3. تريد الإعلان عن الحقول غير الثابتة أو غير النهائية.

فكر في استخدام واجهات إذا:

  1. تتوقع أن تقوم الفئات غير المرتبطة بتنفيذ الواجهة الخاصة بك. على سبيل المثال ، يمكن للعديد من الكائنات غير المرتبطة تنفيذ واجهة Serializable .
  2. تريد تحديد سلوك نوع بيانات معين ، ولكن لا يهمك من يقوم بتنفيذ سلوكه.
  3. تريد الاستفادة من الميراث المتعدد من النوع.

مثال:

فئة الملخص (علاقة A )

Reader هو فئة مجردة.

BufferedReader هو Reader

FileReader هو Reader

FileReader و BufferedReader للأغراض العامة: قراءة البيانات ، وترتبط من خلال فئة Reader .

واجهة (قدرة HAS )

Serializable هو واجهة.

افترض أن لديك فئتين في التطبيق الخاص بك ، والتي تقوم بتنفيذ واجهة Serializable

Employee implements Serializable

Game implements Serializable

هنا لا يمكنك إنشاء أي علاقة من خلال واجهة Serializable بين Employee Game ، والتي تهدف لأغراض مختلفة. كلاهما قادر على تسلسل الدولة وتنتهي المقارنة هناك.

إلقاء نظرة على هذه الوظائف:

كيف يمكنني شرح الفرق بين فئة Interface و Abstract؟


حسناً ، بعد أن قمت بـ "grokked" هذا بنفسي - هنا هي شروط الشخص العادي (لا تتردد في تصحيحي إذا كنت مخطئًا) - أعلم أن هذا الموضوع هو أمر مغرور ، لكن شخصًا آخر قد يتعثر عبره يومًا ما ...

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

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

لماذا استخدام واحد على الآخر؟ الأول يسمح بتعريف أكثر واقعية للأحفاد - وهذا الأخير يسمح لتعدد الأشكال أكبر. هذه النقطة الأخيرة مهمة للمستخدم النهائي / المبرمج ، الذي يمكنه استخدام هذه المعلومات لتنفيذ AP I (nterface) في مجموعة متنوعة من الأشكال / الأشكال لتناسب احتياجاتهم.

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


فكر في استخدام فئات الملخصات إذا كانت أي من هذه العبارات تنطبق على موقفك:

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

حاول استخدام واجهات إذا كانت أي من هذه العبارات تنطبق على حالتك:

  1. تتوقع أن تقوم الفئات غير المرتبطة بتنفيذ الواجهة الخاصة بك. على سبيل المثال ، يتم تنفيذ الواجهات القابلة للمقارنة و Cloneable بواسطة العديد من الفئات غير المرتبطة.
  2. تريد تحديد سلوك نوع بيانات معين ، ولكن لا يهمك من يقوم بتنفيذ سلوكه.
  3. تريد الاستفادة من الميراث متعددة.

Source


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

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

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

تم النسخ من:
http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx


في java ، يمكنك أن ترث من فئة واحدة (مجردة) إلى وظيفة "توفير" ، ويمكنك تنفيذ العديد من الواجهات "لضمان" وظيفة


سنتى:

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

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

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

مثال (بدائية جداً!): ضع في الاعتبار فئة أساسية تسمى "العميل" والتي تحتوي على طرق مجردة مثل CalculatePayment() و CalculateRewardPoints() وبعض الطرق غير المجردة مثل GetName() و SavePaymentDetails() .

سوف ترث الفئات المتخصصة مثل RegularCustomer و GoldCustomer من الفئة الأساسية Customer وتنفيذ منطق الأسلوب CalculateRewardPoints() الخاص به و CalculateRewardPoints() ولكن إعادة استخدام أساليب GetName() و SavePaymentDetails() .

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

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


كتبت مقالا عن ذلك:

دروس مجردة وواجهات

تلخيص:

عندما نتحدث عن الفصول التجريدية ، فإننا نحدد خصائص نوع الكائن. تحديد ما هو كائن .

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


أعتقد أن الطريقة الأكثر إيجازًا لوضعها هي ما يلي:

الخصائص المشتركة => فئة مجردة.
الوظيفة المشتركة => الواجهة.

ووضعها بإيجاز أقل ...

مثال عن فئة الملخص:

public abstract class BaseAnimal
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }
}

public class Dog : BaseAnimal
{
    public Dog() : base(4) { }
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }
}

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

public static int CountAllLegs(List<BaseAnimal> animals)
{
    int legCount = 0;
    foreach (BaseAnimal animal in animals)
    {
        legCount += animal.NumberOfLegs;
    }
    return legCount;
}

مثال على واجهة:

public interface IMakeSound
{
    void MakeSound();
}

public class Car : IMakeSound
{
    public void MakeSound() => Console.WriteLine("Vroom!");
}

public class Vuvuzela : IMakeSound
{
    public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");        
}

لاحظ هنا أن Vuvuzelas and Cars هما شيئان مختلفان تمامًا ، ولكنهما يتمتعان بوظيفة مشتركة: إجراء صوت. وبالتالي ، فإن الواجهة منطقية هنا. علاوة على ذلك ، سيسمح للمبرمجين بتجميع أشياء تجعل الأصوات معًا تحت واجهة مشتركة - IMakeSound في هذه الحالة. باستخدام هذا التصميم ، يمكنك كتابة التعليمة البرمجية التالية:

List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());

foreach (IMakeSound soundMaker in soundMakers)
{
    soundMaker.MakeSound();
}

هل يمكن أن تخبر ماذا سينتج؟

أخيرا ، يمكنك الجمع بين الاثنين.

المثال المشترك:

public interface IMakeSound
{
    void MakeSound();
}

public abstract class BaseAnimal : IMakeSound
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }

    public abstract void MakeSound();
}

public class Cat : BaseAnimal
{
    public Cat() : base(4) { }

    public override void MakeSound() => Console.WriteLine("Meow!");
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }

    public override void MakeSound() => Console.WriteLine("Hello, world!");
}

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

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


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


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

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


بالنسبة لي ، كنت سأذهب مع واجهات في كثير من الحالات. لكني أفضل الفصول التجريدية في بعض الحالات.

تشير الفصول في OO generaly إلى التنفيذ. أستخدم فصول دراسية مجردة عندما أريد فرض بعض تفاصيل التنفيذ على الأطفال الآخرين الذين أذهب معهم باستخدام واجهات.

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


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


عندما تفعل ما هو شيء بسيط للغاية إذا كان لديك مفهوم واضح في ذهنك.

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

في حين أنه من أجل تنفيذ الواجهات ، فإن العلاقة "يمكن أن تكون". على سبيل المثال ، الكلب يمكن أن يكون كلب تجسس. الكلب يمكن أن يكون كلب السيرك. كلب يمكن أن يكون كلب السباق. مما يعني أنك تطبق أساليب معينة للحصول على شيء ما.

آمل أن أكون واضحا.


your answer is right but the interviewer needs you to differentiate according to software engineering perspective not according to the details of Java.

Simple words:

An Interface is like the interface of a shop anything that is shown on it should be there in the shop, so any method in the Interface must be there implemented in the concrete class. Now what if some classes share some exact methods and varies in others. Suppose the Interface is about a shop that contains two things and suppose we have two shops both contain sport equipment but one has clothes extra and the other has shoes extra. So what you do is making an abstract class for Sport that implements the Sports method and leave the other method unimplemented. Abstract class here means that this shop doesn't exist itself but it is the base for other classes/shops. This way you are organising the code, avoiding errors of replicating the code, unifying the code, and ensuring re-usability by some other class.





oop inheritance interface abstract-class