Jest - Is-a
W reprezentacji wiedzy , programowaniu zorientowanym obiektowo i projektowaniu (patrz architektura programu zorientowanego obiektowo ), is-a ( is_a lub is a ) to relacja subsumpcji między abstrakcjami (np. Typami , klasami ), w której jedna klasa A jest podklasą innej Klasa B (a więc i B jest nadrzędna z a ). Innymi słowy, typ A jest podtypem typu B, gdy specyfikacja A implikuje specyfikację B. Oznacza to, że każdy obiekt (lub klasa), który spełnia specyfikację A, spełnia również specyfikację B, ponieważ specyfikacja B jest słabsza.
Is-a związek jest Kontrastuje z ma-a ( has_a lub ma ) związek pomiędzy typów (klas); mylenie relacji ma-a i jest-a jest częstym błędem podczas projektowania modelu (np. programu komputerowego ) relacji między obiektem a obiektem podrzędnym w świecie rzeczywistym. Is-a związek można również przeciwstawić instancji od relacji pomiędzy przedmiotami (wystąpienia) i typu (klas): patrz typu znak różnicy .
Podsumowując relacje, są:
-
hiperonim - hiponim ( nadtyp / nadklasa -podtyp / podklasa) relacje między typami (klasami) określające hierarchię taksonomiczną, gdzie
- na subsumcji stosunku: a hyponym (podtyp podklasy) ma typ-o ( is-a ) związek z hyperonym (supertypem, nadklasy);
-
holonim - meronim (całość / jednostka / pojemnik-część / składnik / element) relacje między typami (klasami) określające hierarchię dzierżawczą, gdzie
- dla relacji agregacji (tj. bez własności):
- holonym (cały) ma HAS w związku z jego meronym (częściowo)
- dla relacji układowej (tj. z prawem własności):
- meronim (składnik) ma część związku ze swoim holonimem (podmiotem),
- na szczelność względem:
- meronim (członek) ma powiązanie członka ze swoim holonimem ( kontener );
- dla relacji agregacji (tj. bez własności):
- relacje pojęcie – obiekt (typ – token) między typami (klasami) i obiektami (instancjami), gdzie
- token (obiekt) ma relację instancji ze swoim typem (klasą).
Przykłady podtypów
Podtypowanie umożliwia zastąpienie danego typu innym typem lub abstrakcją. Subtyping mówi celu utworzenie is-a relacja między podtypu i jakimś istniejącym abstrakcji, bezpośrednio lub pośrednio, w zależności od wsparcia językowego. Zależność można wyrazić jawnie poprzez dziedziczenie w językach, które obsługują dziedziczenie jako mechanizm podtypów.
C ++
Poniższy kod C ++ ustanawia jawną relację dziedziczenia między klasami B i A , gdzie B jest zarówno podklasą, jak i podtypem A i może być używany jako A wszędzie tam, gdzie określono B (za pomocą odwołania, wskaźnika lub samego obiektu ).
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.
}
Pyton
Poniższy kod Pythona ustanawia jawną relację dziedziczenia między klasami B i A , gdzie B jest zarówno podklasą, jak i podtypem A i może być używany jako A wszędzie tam, gdzie jest wymagane 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.
W poniższym przykładzie typ (a) jest typem „zwykłym”, a typ (typ (a)) jest metatypem. Chociaż w przypadku dystrybucji wszystkie typy mają ten sam metatyp ( PyType_Type , który jest również jego własnym metatypem), nie jest to wymagane. Typ klas klasycznych, znany jako types.ClassType , można również uznać za odrębny metatyp.
>>> a = 0
>>> type(a)
<type 'int'>
>>> type(type(a))
<type 'type'>
>>> type(type(type(a)))
<type 'type'>
>>> type(type(type(type(a))))
<type 'type'>
Jawa
W Javie relacja is- między parametrami typu jednej klasy lub interfejsu a parametrami typu innej jest określana przez klauzule extends i implements .
Używając klas Collections, ArrayList <E> implementuje List <E>, a List <E> rozszerza Collection <E>. Więc ArrayList <String> jest podtypem List <String>, który jest podtypem Collection <String>. Relacja podtypów jest zachowywana automatycznie między typami. Podczas definiowania interfejsu PayloadList, który kojarzy opcjonalną wartość typu ogólnego P z każdym elementem, jego deklaracja może wyglądać następująco:
interface PayloadList<E, P> extends List<E> {
void setPayload(int index, P val);
...
}
Następujące parametryzacje PayloadList są podtypami List <String>:
PayloadList<String, String>
PayloadList<String, Integer>
PayloadList<String, Exception>
Zasada substytucji Liskova
Zasada podstawienia Liskova wyjaśnia właściwość: „Jeśli dla każdego obiektu o1 typu S istnieje obiekt o2 typu T taki, że dla wszystkich programów P zdefiniowanych w kategoriach T zachowanie P pozostaje niezmienione, gdy o1 jest zastępowane za o2, to S jest podtypem T, ” . Poniższy przykład pokazuje naruszenie 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));
}
Oczywiście funkcja DrawShape jest źle sformatowana. Musi wiedzieć o wszystkich klasach pochodnych klasy Shape. Należy to również zmienić za każdym razem, gdy tworzona jest nowa podklasa Shape. W projektowaniu zorientowanym obiektowo wielu postrzega tę strukturę jako anatemę.
Oto bardziej subtelny przykład naruszenia 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;
};
Działa to dobrze, ale jeśli chodzi o klasę Square, która dziedziczy klasę Rectangle, narusza LSP, mimo że relacja is-a zachodzi między Rectangle i Square. Ponieważ kwadrat jest prostokątny. Poniższy przykład zastępuje dwie funkcje, Setwidth i SetHeight, aby rozwiązać problem. Ale naprawienie kodu oznacza, że projekt jest wadliwy.
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);
}
Poniższy przykład, funkcja g działa tylko dla klasy Rectangle, ale nie dla Square, więc zasada open-closed została naruszona.
void g(Rectangle& r)
{
r.SetWidth(5);
r.SetHeight(4);
assert(r.GetWidth() * r.GetHeight()) == 20);
}
Zobacz też
- Dziedziczenie (programowanie obiektowe)
- Zasada substytucji Liskova (w programowaniu obiektowym )
- Subsumowanie
- Jest
- Hypernymy (i supertypem )
- Hyponimia (i podtyp )
- Ma
Uwagi
Bibliografia
- Ronald J. Brachman ; Czym jest i czym nie jest IS-A. Analiza powiązań taksonomicznych w sieciach semantycznych . Komputer IEEE, 16 (10); Październik 1983
- Jean-Luc Hainaut, Jean-Marc Hick, Vincent Englebert, Jean Henrard, Didier Roland: Zrozumienie implementacji relacji IS-A . ER 1996: 42–57