language agnostic - ماذا يعني "البرنامج إلى واجهة"؟




language-agnostic oop (20)

Q: - ... "You could use any class that implements interface?"
A: - Yes.

Q: -... "When would you need to do that?"
A: - Each time you need a class(es) that implements interface(s).

Note: we couldn't instantiate an interface not implemented by a class - True.

  • لماذا ا؟
  • because interface has only methods prototypes, not definitions (just functions names, not their logic)

AnIntf anInst = new Aclass();
// we could do this only if Aclass implements AnIntf.
// anInst will have Aclass reference.

ملحوظة:
Now we could understand what happend if Bclass and Cclass implements same Dintf.

Dintf bInst = new Bclass();  
// now we could call all Dintf functions implemented (defined) in Bclass.

Dintf cInst = new Cclass();  
// now we could call all Dintf functions implemented (defined) in Cclass.

What we have:
same interface prototypes (functions names in interface), and call different implementations.

Bibliography:
Prototypes - wikipedia

https://code.i-harness.com

لقد رأيت هذا ذكر عدة مرات وأنا لست واضحا على ما يعنيه. متى ولماذا تفعل هذا؟

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

هل الأمر كذلك إذا كنت ستفعل:

IInterface classRef = new ObjectWhatever()

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

آسف إذا غاب عن النقطة تماما.


أنا في وقت متأخر قادم على هذا السؤال ، ولكن أريد أن أذكر هنا أن سطر "البرنامج إلى واجهة ، وليس تنفيذ" كان بعض النقاش الجيد في كتاب أنماط (Goop of Four) تصميم GoF.

وذكر ، في ص. 18:

البرنامج إلى واجهة ، وليس التنفيذ

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

وفوق ذلك ، بدأت مع:

هناك فائدتان للتعامل مع الكائنات فقط من حيث الواجهة المعرّفة بواسطة فئات الملخصات:

  1. يظل العملاء غير مدركين لأنواع محددة من الكائنات التي يستخدمونها ، طالما أن الكائنات تلتزم بالواجهة التي يتوقعها العملاء.
  2. يظل العملاء غير مدركين للفئات التي تطبق هذه الكائنات. لا يعرف العملاء إلا عن الفئة (الخانات) المجردة التي تحدد الواجهة.

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


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

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

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

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


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

بالإضافة إلى ذلك ، ننظر إلى مديري SOLID . هنا سلسلة فيديو

ينتقل من خلال المشفر الثابت (على سبيل المثال إلى حد كبير) ثم ينظر إلى الواجهات ، ويتقدم في النهاية إلى أداة IoC / DI (NInject)


المثال المحدد الذي اعتدت أن أقدمه للطلاب هو أنهم يجب أن يكتبوا

List myList = new ArrayList(); // programming to the List interface

بدلا من

ArrayList myList = new ArrayList(); // this is bad

هذه تبدو نفسها بالضبط في برنامج قصير ، ولكن إذا ذهبت إلى استخدام myList 100 مرة في البرنامج الخاص بك ، يمكنك البدء في رؤية الفرق. يضمن الإعلان الأول أن تقوم فقط باستدعاء الطرق الموجودة على myList التي تم تعريفها بواسطة واجهة List (لذلك لا توجد أساليب محددة من ArrayList ). إذا كنت مبرمجًا على الواجهة بهذه الطريقة ، في وقت لاحق يمكنك أن تقرر أنك تحتاج بالفعل

List myList = new TreeList();

وعليك فقط تغيير شفرتك في تلك النقطة. أنت تعلم بالفعل أن بقية شفرتك لا تفعل أي شيء يمكن كسره عن طريق تغيير التطبيق لأنك مبرمج على الواجهة .

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

public ArrayList doSomething(HashMap map);

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

public List doSomething(Map map);

لا يهم الآن نوع List التي ترجع إليها ، أو نوع Map يتم تمريرها كمعلمة. لن تجبر التغييرات التي تجريها داخل طريقة doSomething على تغيير رمز الاتصال.


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


تقول البرمجة إلى واجهة: "أحتاج إلى هذه الوظيفة ولا يهمني من أين تأتي".

خذ بعين الاعتبار (في Java) ، واجهة List مقابل فئات ملموسة ArrayList و LinkedList . إذا كان كل ما يهمني هو أن لدي بنية بيانات تحتوي على عناصر بيانات متعددة يجب الوصول إليها عبر التكرار ، فسأختار List (وهذا يمثل 99٪ من الوقت). إذا كنت أعلم أنني أحتاج إلى إدراج / حذف في الوقت الثابت من أيٍّ من طرفي القائمة ، فقد أختار التنفيذ الملموس لـ LinkedList (أو على الأرجح ، استخدم واجهة Queue ). إذا كنت أعلم أنني بحاجة إلى الوصول العشوائي عن طريق الفهرس ، فسأقوم باختيار فئة الخرسانة ArrayList .


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

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


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


هناك الكثير من التفسير هناك ، ولكن لجعله أكثر بساطة. خذ على سبيل المثال List . يمكن للمرء تنفيذ قائمة مع:

  1. مجموعة داخلية
  2. قائمة مرتبطة
  3. التنفيذ الأخرى

من خلال البناء على واجهة ، قل List . أنت فقط رمز لتعريف قائمة أو ما يعني List في الواقع.

يمكنك استخدام أي نوع من التنفيذ array تنفيذ array داخليًا. ولكن لنفترض أنك ترغب في تغيير التنفيذ لسبب ما ، لنقل خطأ أو أداء. ثم عليك فقط تغيير List<String> ls = new ArrayList<String>() تعريف List<String> ls = new ArrayList<String>() إلى List<String> ls = new LinkedList<String>() .

لا يوجد مكان آخر في التعليمات البرمجية ، سيكون عليك تغيير أي شيء آخر ؛ لأن كل شيء آخر تم بناؤه على تعريف List .


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

// if I want to add search capabilities to my application and support multiple search
// engines such as google, yahoo, live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

بعد ذلك يمكنني إنشاء GoogleSearchProvider و YahooSearchProvider و LiveSearchProvider وما إلى ذلك.

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

ثم إنشاء JpegImageLoader ، GifImageLoader ، PngImageLoader ، إلخ.

تعمل معظم الوظائف الإضافية ووظائف المكون الإضافي خارج الواجهات.

استخدام شائع آخر هو لنمط مستودع التخزين. قل أرغب في تحميل قائمة الرموز البريدية من مصادر مختلفة

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

ثم يمكنني إنشاء XMLZipCodeRepository ، SQLZipCodeRepository ، CSVZipCodeRepository ، إلخ. بالنسبة لتطبيقات الويب الخاصة بي ، غالباً ما أقوم بإنشاء مستودعات XML في وقت مبكر حتى أتمكن من الحصول على شيء وتشغيله قبل أن تكون قاعدة بيانات Sql جاهزة. بمجرد أن تكون قاعدة البيانات جاهزة ، اكتب SQLRepository لاستبدال إصدار XML. تبقى بقية التعليمة البرمجية الخاصة بي دون تغيير منذ تشغيل soley إيقاف الواجهات.

يمكن أن تقبل الطرق واجهات مثل:

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}

يجب أن تنظر إلى انقلاب التحكم:

في مثل هذا السيناريو ، لن تكتب هذا:

IInterface classRef = new ObjectWhatever();

ستكتب شيئًا كهذا:

IInterface classRef = container.Resolve<IInterface>();

من شأن ذلك الانتقال إلى إعداد مستند إلى القواعد في كائن container ، وإنشاء الكائن الفعلي لك ، والذي قد يكون ObjectWhatever. الشيء المهم هو أنه يمكنك استبدال هذه القاعدة بشيئ استخدم نوعًا آخر من الكائنات تمامًا ، وستظل الشفرة تعمل.

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

هذا من شأنه أن يأتي في متناول اليدين عند تمرير المعلمات.

أما بالنسبة للسؤال الذي يتلقاها بين قوسين "أيضاً ، كيف يمكنك كتابة أسلوب يأخذ في كائن يقوم بتنفيذ واجهة؟ هل هذا ممكن؟" ، في C # ، يمكنك ببساطة استخدام نوع الواجهة لنوع المعلمة ، كما يلي:

public void DoSomethingToAnObject(IInterface whatever) { ... }

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

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

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

اسمحوا لي أن أقدم لكم مثالا ملموسا.

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

الآن ، بما أن عناصر التحكم ترث من فئات محددة مسبقًا لا نملك السيطرة عليها ، يمكننا القيام بأحد الأمور الثلاثة التالية:

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

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


In simple terms... If I'm writing a new class Swimmer to add the functionality swim() and need to use an object of class say Dog, and this Dog class implements interface Animal which declares swim()[To better understand...you may draw a diagram as to what I am talking about]. At the top of the hierarchy(Animal) it's very abstract while at the bottom (Dog) it's very concrete. The way I think about "programming to interfaces" is that, as I write Swimmer class, I want to write my code against the interface that's as far up that hierarchy which in this case is Animal object. An interface is free from implementation details and thus makes your code loosely-coupled. The implementation details can be changed with time, however it would not affect the remaining code since all you are interacting is with the interface and not the implementation. You don't care what the implementation is like...all you know is that there will be a class that would implement the interface.


Program to an interface allows to change implementation of contract defined by interface seamlessly. It allows loose coupling between contract and specific implementations.

IInterface classRef = new ObjectWhatever()

You could use any class that implements IInterface? When would you need to do that?

Have a look at this SE question for good example.

Why should the interface for a Java class be preferred?

does using an Interface hit performance?

if so how much?

نعم فعلا. It will have slight performance overhead in sub-seconds. But if your application has requirement to change the implementation of interface dynamically, don't worry about performance impact.

how can you avoid it without having to maintain two bits of code?

Don't try to avoid multiple implementations of interface if your application need them. In absence of tight coupling of interface with one specific implementation, you may have to deploy the patch to change one implementation to other implementation.

One good use case: Implementation of Strategy pattern:

Real World Example of the Strategy Pattern


Also I see a lot of good and explanatory answers here, so I want to give my point of view here, including some extra information what I noticed when using this method.

Unit testing

For the last two years, I have written a hobby project and I did not write unit tests for it. After writing about 50K lines I found out it would be really necessary to write unit tests. I did not use interfaces (or very sparingly) ... and when I made my first unit test, I found out it was complicated. لماذا ا؟

Because I had to make a lot of class instances, used for input as class variables and/or parameters. So the tests look more like integration tests (having to make a complete 'framework' of classes since all was tied together).

Fear of interfaces So I decided to use interfaces. My fear was that I had to implement all functionality everywhere (in all used classes) multiple times. In some way this is true, however, by using inheritance it can be reduced a lot.

Combination of interfaces and inheritance I found out the combination is very good to be used. I give a very simple example.

public interface IPricable
{
    int Price { get; }
}

public interface ICar : IPricable

public abstract class Article
{
    public int Price { get { return ... } }
}

public class Car : Article, ICar
{
    // Price does not need to be defined here
}

This way copying code is not necessary, while still having the benefit of using a car as interface (ICar).


C++ explanation.

Think of an interface as your classes public methods.

You then could create a template that 'depends' on these public methods in order to carry out it's own function (it makes function calls defined in the classes public interface). Lets say this template is a container, like a Vector class, and the interface it depends on is a search algorithm.

Any algorithm class that defines the functions/interface Vector makes calls to will satisfy the 'contract' (as someone explained in the original reply). The algorithms don't even need to be of the same base class; the only requirement is that the functions/methods that the Vector depends on (interface) is defined in your algorithm.

The point of all of this is that you could supply any different search algorithm/class just as long as it supplied the interface that Vector depends on (bubble search, sequential search, quick search).

You might also want to design other containers (lists, queues) that would harness the same search algorithm as Vector by having them fulfill the interface/contract that your search algorithms depends on.

This saves time (OOP principle 'code reuse') as you are able to write an algorithm once instead of again and again and again specific to every new object you create without over-complicating the issue with an overgrown inheritance tree.

As for 'missing out' on how things operate; big-time (at least in C++), as this is how most of the Standard TEMPLATE Library's framework operates.

Of course when using inheritance and abstract classes the methodology of programming to an interface changes; but the principle is the same, your public functions/methods are your classes interface.

This is a huge topic and one of the the cornerstone principles of Design Patterns.


Interface is like contract where you want your implementation class to implement methods written in contract(Interface).Since java does not provide multiple inheritance,programming to interface is a good way to achieve purpose of multiple inheritance.If you have a class A that is already extending some other class B but you want that class A should also follow certain guidelines or implement certain contract then you can do so by programming to interface strategy.


It can be advantageous to program to interfaces, even when we are not depending on abstractions.

Programming to interfaces forces us to use a contextually appropriate subset of an object. That helps because it:

  1. prevents us from doing contextually inappropriate things, and
  2. lets us safely change the implementation in the future.

For example, consider a Person class that implements the Friend and the Employee interface.

class Person implements AbstractEmployee, AbstractFriend {

}

In the context of the person's birthday, we program to the Friend interface, to prevent treating the person like an Employee .

function party() {
    const friend: Friend = new Person("Kathryn");
    friend.HaveFun();
}

In the context of the person's work, we program to the Employee interface, to prevent blurring workplace boundaries.

function workplace() {
    const employee: Employee = new Person("Kathryn");
    employee.DoWork();
}

عظيم. We have behaved appropriately in different contexts, and our software is working well.

Far into the future, if our business changes to work with dogs, we can change the software fairly easily. First, we create Dog class that implements both Friend and Employee . Then, we safely change new Person() to new Dog() . Even if both functions have thousands of lines of code, that simple edit will work because we know the following are true:

  1. Function party uses only the Friend subset of Person .
  2. Function workplace uses only the Employee subset of Person .
  3. Class Dog implements both the Friend and Employee interfaces.

On the other hand, if either party or workplace were to have programmed against Person , there would be a risk of both having Person -specific code. Changing from Person to Dog would require us to comb through the code to extirpate any Person -specific code that Dog does not support.

The moral : programming to interfaces helps our code to behave appropriately and to be ready for change. It also prepares our code to depend on abstractions, which brings even more advantages.


short story:Postman is asked to go home by home and receive the covers contains (letters,documents,cheques,giftcard,application,loveletter) with address written on it to deliver.

Suppose there is no cover and ask post man to go home by home and receive all the things and deliver to other person the postman can get confuse,

so better wrap it with cover(in our story it is interface) then he will do his job fine.

Now postman job is to receive and deliver the covers only..(he dont bothered what is inside in the cover).

Create type of interface not actual type, but implement with actual type.

Create to interface means your components get Fits into the rest of code easily

I give you example.

you have AirPlane interface as below.

interface Airplane{
    parkPlane();
    servicePlane();
}

Suppose you have methods in your Controller class of Planes like

parkPlane(Airplane plane)

و

servicePlane(Airplane plane)

implemented in your program. It will not BREAK your code. I mean, it need not to change as long as it accepts arguments as AirPlane .

Because it will accept any Airplane despite of actual type, flyer , highflyr , fighter , etc.

Also, in a collection:

List<Airplane> plane; // Will take all your planes.

The following example will clear your understanding.

You have a fighter plane that implements it, so

public class Fighter implements Airplane {

    public void  parkPlane(){
        // Specific implementations for fighter plane to park
    }
    public void  servicePlane(){
        // Specific implementatoins for fighter plane to service.
    }
}

The same thing for HighFlyer and other clasess:

public class HighFlyer implements Airplane {

    public void  parkPlane(){
        // Specific implementations for HighFlyer plane to park
    }

    public void  servicePlane(){
        // specific implementatoins for HighFlyer plane to service.
    }
}

Now think your controller classes using AirPlane several times,

Suppose your Controller class is ControlPlane like below,

public Class ControlPlane{ 
 AirPlane plane;
 // so much method with AirPlane reference are used here...
}

here magic comes as

you may make your new AirPlane type instances as many as you want and you are not changing

code of ControlPlane class.

you can add instance..

JumboJetPlane // implementing AirPlane interface.
AirBus        // implementing AirPlane interface.

you may remove instances.. of previously created types too.


في ما يلي مثال بسيط لتوضيحه عند برمجة نظام حجز رحلة.

//This interface is very flexible and abstract
    addPassenger(Plane seat, Ticket ticket); 

//Boeing is implementation of Plane
    addPassenger(Boeing747 seat, EconomyTicket ticket); 
    addPassenger(Cessna, BusinessClass ticket);


    addPassenger(J15, E87687); 






interface