في تمثيل المعرفة، البرمجة والتصميم الكينوني (انظر بنية البرنامج الكينوني ) ، ((is_a or is a) ) هي علاقة من العلاقات الفرعية خاصية التجريد كما في ( الكلاسات، الفئات ) ، حيث يكون كلاس A هو فئة فرعية من كلاس B أخرى (وبالتالي فإن B هي فئة فائقة من A ). بمعنى آخر، النوع A هو نوع فرعي من النوع B عندما تتضمن مواصفات A مواصفات B. أي أن أي كائن (أو فئة) يفي بمواصفات A يفي أيضًا بمواصفات B في نفس الوقت، لأن مواصفات B أضعف.
يجب أن تكون العلاقة is-a متناقضة في مع علاقة ( has_a or has a ) بين أنواع (الكلاسات) ؛ إن الخلط بين العلاقات هو has-a و is-a هو خطأ شائع عند تصميم نموذج (على سبيل المثال، برنامج كمبيوتر ) للعلاقة الواقعية بين كائن ما ومرؤوسه. ويمكن لهذه العلاقة ان تتعارض مع مثيلاتها من العلاقات الباقية والتي يمكن أن تكون بين الكائنات (حالات) وأنواع (الكلاسات): انظر " من نوع رمزي التمييز " و " علاقات من نوع رمزي ". [1]
لتلخيص العلاقات لدينا :
- Hyperonym - الاختصار ( supertype – subtype ) العلاقات بين الكلاسات التي تحدد التسلسل الهرمي للتصنيف، حيث
- بالنسبة لعلاقة الاستيعاب : الاختصار (النوع الفرعي، الفئة الفرعية) له علاقة من نوع ( is-a ) ويكون الاختصار (supertype ، superclass) ؛
- holonym - العلاقات المرادفة وتأتي بالتسلسل الهرمي التالي (كامل / الكيان / جزء الحاوية / المكون / العضو) بين الأنواع (الفئات) التي تحدد التسلسل الهرمي التملك، حيث تكون
- العلاقات بين المفهوم والكائن (النوع المميز) بين الأنواع (الفئات) والكائنات (الحالات) ، حيث
- الرمز المميز (كائن) له علاقة مثيل بنوعه (الفئة).
يتيح التصنيف الفرعي استبدال نوع معين بنوع أو تجريد النوع الاخر. التصنيف الفرعي يكون لإنشاء علاقة is-a بين نوع فرعي وبعض التجريد القائم، إما علنيا أو ضمنيا، اعتمادا على دعم اللغة. يمكن التعبير عن العلاقة بشكل صريح عبر الوراثة باللغات التي تدعم الوراثة كآلية تصنيف فرعي.
ينشئ كود C ++ التالي علاقة وراثية صريحة بين الفئتين B و A ، حيث B هي فئة فرعية ونوع فرعي اخر من A ، ويمكن استخدامها ك A حيثما يتم تحديد B (عبر مرجع أو مؤشر أو الكائن نفسه) ).
class A { public: void DoSomethingALike() const {} }; class B : public A { public: void DoSomethingBLike() const {} }; void UseAnA(A const& some_A) { some_A.DoSomethingALike(); } void SomeFunc() { B b; UseAnA(b); // b can be substituted for an A. }
ينشئ رمز بايثون التالي علاقة وراثية صريحة بين الفئتين B و A ، حيث يكون B فئة فرعية ونوعًا فرعيًا من A ، ويمكن استخدامه ك A حيثما كان مطلوبًا B.
class A: def do_something_a_like(self): pass class B(A): def do_something_b_like(self): pass def use_an_a(some_a): some_a.do_something_a_like() def some_func(): b = B() use_an_a(b) # b can be substituted for an A.
المثال التالي، النوع (أ) هو نوع "عادي" ، والنوع (النوع (أ)) هو نوع من بيانات. على الرغم من توزيع جميع الأنواع على نفس نوع البيانات الوصفية (PyType_Type ، وهو أيضًا نوعها الخاص) ، إلا أن هذا ليس شيء متطلب. نوع الفصول الكلاسيكية، والمعروف باسم الأنواع. ClassType ، يمكن أيضًا اعتباره نوعًا متميزًا. [3]
>>> a = 0 >>> type(a) <type 'int'> >>> type(type(a)) <type 'type'> >>> type(type(type(a))) <type 'type'> >>> type(type(type(type(a)))) <type 'type'>
في Java ، هي علاقة بين معلمات لفئة أو واجهة واحدة، ومعلمات النوع لفئة أخرى يتم تحديدها بواسطة الجمل الموسعة وتنفذ .
باستخدام فئات المجموعات، المصفوفة <E>، ترث القائمة ووبالتالي توسع المجموعة <E>. لذا فإن المصفوفة من نوع string هو نوع فرعي من القائمة <String> ، وهو نوع فرعي من المجموعة <String>. يتم الحفاظ على علاقة الأنواع الفرعية والأنواع تلقائيًا. عندما نحدد واجهة، PayloadList ، تربط قيمة اختيارية من النوع العام P بكل عنصر، قد يبدو إعلانه كما يلي:
interface PayloadList<E, P> extends List<E> { void setPayload(int index, P val); ... }
المعلمات التالية من PayloadList هي أنواع فرعية من القائمة <سلسلة>:
PayloadList<String, String> PayloadList<String, Integer> PayloadList<String, Exception>
يشرح مبدأ استبدال Liskov خاصية، "إذا كان لكل كائن o1 من النوع S يوجد كائن o2 من النوع T بحيث لا يتغير سلوك P لجميع البرامج P المحددة من حيث T ، عندما يتم استبدال o1 بـ o2 ثم S هو نوع فرعي من T " . [4] يوضح المثال التالي انتهاك LSP.
void DrawShape(const Shape& s) { if (typeid(s) == typeid(Square)) DrawSquare(static_cast<Square&>(s)); else if (typeid(s) == typeid(Circle)) DrawCircle(static_cast<Circle&>(s)); }
من الواضح أن الدالة DrawShape تم تنسيقها بشكل سيئ. يجب أن تعرف كل فئة مشتقة من فئة الشكل. أيضا، يجب تغييره كلما تم إنشاء فئة فرعية جديدة من الشكل. في التصميم الموجه للكائنات
فيما يلي مثال أكثر دقة على انتهاك LSP:
class Rectangle { public: void SetWidth(double w) { itsWidth = w; } void SetHeight(double h) { itsHeight = h; } double GetHeight() const { return itsHeight; } double GetWidth() const { return itsWidth; } private: double itsWidth; double itsHeight; };
يعمل هذا بشكل جيد ولكن عندما يتعلق الأمر بالفئة المربعة، التي ترث فئة المستطيل، فإنها تنتهك LSP على الرغم من أن العلاقة هي علاقة بين المستطيل والمربع. لأن المربع مستطيل. يتجاوز المثال التالي وظيفتين، Setwidth و SetHeight ، لإصلاح المشكلة. لكن إصلاح الرمز يعني أن التصميم معيب.
public class Square : Rectangle { public: virtual void SetWidth(double w); virtual void SetHeight(double h); }; void Square::SetWidth(double w) { Rectangle::SetWidth(w); Rectangle::SetHeight(w); } void Square::SetHeight(double h) { Rectangle::SetHeight(h); Rectangle::SetWidth(h); }
المثال التالي، الوظيفة g تعمل فقط لفئة المستطيل ولكن ليس لـ Square ، وبالتالي تم انتهاك مبدأ الإغلاق المفتوح.
void g(Rectangle& r) { r.SetWidth(5); r.SetHeight(4); assert(r.GetWidth() * r.GetHeight()) == 20); }
مقالات ذات صلة
- Inheritance (object-oriented programming)
- Liskov substitution principle (in object-oriented programming)
- Subsumption
- Is-a
- Has-a
- تمييز نوع الرمز المميز
- See also Containment (computer programming).
- Guido van Rossum. "Subtyping Built-in Types". مؤرشف من الأصل في 14 مايو 202002 أكتوبر 2012.
- Liskov, Barbara (May 1988). Data Abstraction and Hierarchy ( كتاب إلكتروني PDF ). SIGPLAN Notices. مؤرشف من الأصل ( كتاب إلكتروني PDF ) في 08 يوليو 2019.
- Ronald J. Brachman; What IS-A is and isn't. An Analysis of Taxonomic Links in Semantic Networks. IEEE Computer, 16 (10); October 1983
- Jean-Luc Hainaut, Jean-Marc Hick, Vincent Englebert, Jean Henrard, Didier Roland: Understanding Implementations of IS-A Relations. ER 1996: 42-57