Классы. Наследование

Материал из wikiru.visual-prolog.com

Обсуждаемы далее механизмы наследования включают понятие "правила видимости". В вульгарной интерпретации под правилом видимости мы понимаем возможность обращения к базовым элементам языка (константам, доменам, предикатам, клаузам и фактам) одной сущности из какой-либо другой сущности. Сущностями являются в данном случае классы и объекты.

Примечание. К правилам видимости мы не относим вопросы включения текстов интерфейсов, классов и имплементаций в соответствующие файлы проекта. Такие коллизии включения должны быть разрешены корректно.

В VIP все правила видимости определяются местом декларации. Таким местом может быть:

  • декларация класса (class ... end class)
  • декларация интерфейса (interface ... end interface)
  • имплементация класса (implement ... end implement)

Рассмотрим следующие программные конструкции

class parent:parent
end class
 
interface parent
predicates
 helloWorldFromParent:(string Text).
end interface parent
 
implement parent
 clauses
   helloWorldFromParent(Text):-
    write(Text).
end implement parent
 
class child:child
end class
 
interface child
 helloWorldFromChild:(string Text).
end interface child
 
implement child
 inherits parent
 clauses
    helloWorldFromChild(Text):-
       write(Text).
end implement child

Здесь представлены два класса, порождающих объекты: parent (родитель) и child (потомок) helloWorldFromChild(...) - подчиняется правилу public а на helloWorldFromParent(...) - действует правило protected.

У объекта класса child можно вызвать только предикат helloWorldFromChild(...), а из объекта класса child можно обратиться как к предикату helloWorldFromChild(...), так и к предикату helloWorldFromParent(...).

Имя интерфейса является также и именем домена

объединение предикатов нескольких интерфейсов или подмена одного интерфейса другим легко делается с помощью объявления supports, например,

interface myInterface
 supports myInterface1
 supports myInterface2
end interface myInterface

Если у Вас есть интерфейсы myInterface1 и myInterface2, то через myInterface можно оперировать предикатами из myInterface1 и myInterface2 как предикатами одного интерфейса. В добавок myInterface тоже может иметь свой список объявлений предикатов.

Кроме того есть такие возможности, как delegate interface - когда можно передать исполнение предикатов интерфейса объекту, хранящемуся в факте-переменной.

Возможно перекрывать имплементацию предиката(ов) родительского класса имплементацией предиката(ов) дочернего класса, например, родителький класс содержит имплементацию "по умолчанию", а ряд конкретных классов должен реагировать на вызов предикатов особенным образом.

Клаузы для предикаты одного интерфейса могут содержаться в имлементациях разных классов путем использования конструкции predicates from ...

То есть интерфейс есть фасадная часть класса (динамического), а механизмы имплементации могут быть самыми разными.

Я думаю здесь та же история, что и с типизацией в Turbo, PDC и Visual Прологах: технически оправдано и практически ведет к повышению надежности программ.

1. Ни классы, ни интерфейсы не имеют никаких предопределенных предикатов (кроме конструкторов, относящихся только к декларации класса), а видимость фактов предполагает операции над ними и, cоответственно, наличие предопределенных предикатов. 2. Причина дисциплинарного характера - выполнять операции над фактами только через соответствующие предикаты. Глобальные данные должны храниться в объекте, о котором должны знать те, кому положено.

В имплементации происходит наследование классов (точнее - объектов-экземпляров этих классов), а вот наследуются методы или нет - это определяется интерфейсами, которые эти классы поддерживают. Кроме того, предикаты, объявленные внутри имплементации видны только изнутри только этой имплементации.

Ниже я переименовал классы и интерфейсы, чтобы было яснее где что.

class parentClass:parentInterface
end class parentClass
 
interface parentInterface
 predicates
   publicPredicate:().
end interface parentInterface
 
implement parentClass
 clauses
   publicPredicate():-
     write("").
 predicates
   privatePredicate:().
 clauses
  privatePredicate():-
    write("TTT").
end implement parentClass
 
class childClass:childInterface
end class childClass
 
implement childClass
 inherits parentClass
end implement childClass
 
interface childInterface
end interface childInterface

publicPredicate() доступен из класса childClass,а privatePredicate недоступен для использования нигде, кроме как в самом классе parentClass.

  • Интерфейс никак не зависит от класса - это именованный набор предикатов и/или доменов и/или констант.
  • Класс поддерживает некоторый интерфейс (своей имплементацией), если этот интерйес указан в декларации класса.
  • Имплементация всегда соответствует классу и имеет с ним одно имя.
  • Если класс поддерживает интерфейс, то имплементация должна тем или иным образом привести к клаузу для каждого предиката интерфейса.

Поэтому может быть много разных классов , поддерживающих один и тот же интерфейс.

Статический класс не наследуется - у него нет ни конструктора, ни интерфейса, а они необходимы для работы механизма наследования.


Да, класс может поддерживать некий интерфейс и плюс набор статических сущностей.

В имплементации происходит наследование классов, а вот наследуются методы или нет - это определяется интерфейсами, которые эти классы поддерживают.

Из иплементации дочернего класса видны все предикаты, декларированные в интерфейсах родительских классов. При обращении же к дочернему классу видны только предикаты, декларированные в интерфейсе этого дочернего класса.

Рассмотрим пример.

Допустим, есть классы - родители (я опускаю синтаксические детали вроде end class... и похожие)

parentClass_1:Interface_1 
parentClass_2:Interface_2

Имплементации классов parentClass_1 и parentClass_2 поддерживают предикаты, декларированные в интерфейсах Interface1 и Interface2, соответственно.

Допустим, есть дочерний класс childClass:childInterface Пусть есть интерфейс

interface childInterface 
supports Interface_1

Примечание: для такого случая можно было бы иметь декларацию класса в виде childClass:Interface_1

Теперь пусть есть имплементация дочернего класса:

implement childClass
 inherits parentClass_1
 inherits parentClass_2

Что и откуда можно видеть? 1. из имплемнтации childClass видны (могут быть вызваны): a) все предикаты, непосредственно декларированные интерфейсе childInterface B) все предикаты, декларированные интерфейсе Interface_1 с) все предикаты, декларированные интерфейсе Interface_2

2. Из какого-либо класса вне childClass видны (могут быть вызваны) при обращеии к его экземпляру: a) все предикаты, непосредственно декларированные интерфейсе childInterface B) все предикаты, декларированные интерфейсе Interface_1