Это - Is-a
В представлении знаний , объектно-ориентированном программировании и дизайне (см. Объектно -ориентированную программную архитектуру ) is-a ( is_a или is a ) является отношением подчинения между абстракциями (например, типами , классами ), при этом один класс A является подклассом другого. класс B (и так B является суперкласс из A ). Другими словами, тип A является подтипом типа B, когда спецификация A подразумевает спецификацию B. То есть любой объект (или класс), который удовлетворяет спецификации A, также удовлетворяет спецификации B, потому что спецификация B слабее.
Отношение is-a следует противопоставить отношениям has-a ( has_a или has a ) между типами (классами); путаница отношений имеет-а и есть-а является распространенной ошибкой при разработке модели (например, компьютерной программы ) реальных отношений между объектом и его подчиненным. Отношение is-a можно также противопоставить отношениям instance-of между объектами (экземплярами) и типами (классами): см. Различие между типом и маркером .
Подводя итог отношениям, можно выделить:
-
гипероним - гипоним (супертип / суперкласс – подтип / подкласс) отношения между типами (классами), определяющие таксономическую иерархию, где
- для отношения подчинения : гипоним (подтип, подкласс) имеет отношение типа ( является ) со своим гиперонимом (супертип, суперкласс);
-
холоним - мероним (целое / сущность / контейнер – часть / составляющая / член) отношения между типами (классами), определяющие притяжательную иерархию, где
- для отношения агрегации (т.е. без собственности):
- holonym (вся) имеет имеет-а отношения с его meronym (часть),
- для отношения композиции (т.е. с правом собственности):
- meronym (составной) имеет часть Организации отношения с его holonym (лица),
- для отношения включения :
- мероним (член) имеет отношение члена со своим холонимом ( контейнером );
- для отношения агрегации (т.е. без собственности):
- понятие – объект (тип – токен) отношения между типами (классами) и объектами (экземплярами), где
- токен (объект) имеет отношение экземпляра со своим типом (классом).
Примеры подтипов
Подтипирование позволяет заменить данный тип другим типом или абстракцией. Подтипирование сказано учредить есть- связь между подтипом и некоторыми существующими абстракциями, явно или неявно, в зависимости от языковой поддержки. Отношения могут быть явно выражены через наследование на языках, которые поддерживают наследование как механизм выделения подтипов.
C ++
Следующий код 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.
}
Python
Следующий код Python устанавливает явное отношение наследования между классами B и 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.
В следующем примере type (a) - это «обычный» тип, а type (type (a)) - это метатип. Хотя распределенные типы имеют один и тот же метатип ( PyType_Type , который также является его собственным метатипом), это не является обязательным требованием. Тип классических классов, известный как types.ClassType , также можно рассматривать как отдельный метатип.
>>> 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, это-а соотношение между параметрами типа одного класса или интерфейса и параметров типа другого определяются расширяется и реализует положения.
Используя классы Collections, ArrayList <E> реализует List <E>, а List <E> расширяет Collection <E>. Итак, ArrayList <String> является подтипом List <String>, который является подтипом Collection <String>. Связь подтипов сохраняется между типами автоматически. При определении интерфейса PayloadList, который связывает необязательное значение универсального типа P с каждым элементом, его объявление может выглядеть так:
interface PayloadList<E, P> extends List<E> {
void setPayload(int index, P val);
...
}
Следующие параметризации PayloadList являются подтипами List <String>:
PayloadList<String, String>
PayloadList<String, Integer>
PayloadList<String, Exception>
Принцип подстановки Лискова
Принцип подстановки Лискова объясняет свойство: «Если для каждого объекта o1 типа S существует объект o2 типа T, такой, что для всех программ P, определенных в терминах T, поведение P не изменяется, когда o1 заменяется на o2, то S является подтипом T, " . В следующем примере показано нарушение 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 плохо отформатирована. Он должен знать обо всех производных классах класса Shape. Кроме того, его следует изменять всякий раз, когда создается новый подкласс Shape. В объектно-ориентированном дизайне многие рассматривают эту структуру как анафему.
Вот более тонкий пример нарушения 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;
};
Это хорошо работает, но когда дело доходит до класса Square, который наследует класс Rectangle, он нарушает LSP, хотя между Rectangle и Square сохраняется связь is-a . Потому что квадрат прямоугольный. В следующем примере для устранения проблемы переопределяются две функции, 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 работает только для класса Rectangle, но не для Square, поэтому принцип открыт-закрытость был нарушен.
void g(Rectangle& r)
{
r.SetWidth(5);
r.SetHeight(4);
assert(r.GetWidth() * r.GetHeight()) == 20);
}
Смотрите также
- Наследование (объектно-ориентированное программирование)
- Принцип подстановки Лискова (в объектно-ориентированном программировании )
- Потребление
- Это
- Гипернимия (и супертип )
- Гипонимия (и подтип )
- Имеет
Заметки
Рекомендации
- Рональд Дж. Брахман ; Что такое IS-A, а что нет. Анализ таксономических связей в семантических сетях . IEEE Computer, 16 (10); Октябрь 1983 г.
- Жан-Люк Эно, Жан-Марк Хик, Винсент Энгльбер, Жан Хенрар, Дидье Ролан: понимание реализации отношений IS-A . ER 1996: 42-57