Классы. Наследование: различия между версиями

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

 
(не показана 1 промежуточная версия этого же участника)
Строка 9: Строка 9:
<vip>
<vip>
predicates
predicates
   выделитьИзФайлаОтрезокТекстаСЗаданнойДлиной:(string ИмяФайла, unsigned ЧислоСимоволов) ->string
   выделитьИзФайлаОтрезокТекстаСЗаданнойДлиной:(string FileName, unsigned ЧислоСимоволов) ->string
clauses
clauses
   выделитьИзФайлаОтрезокТекстаСЗаданнойДлиной(ИмяФайла,ЧислоСимоволов)=ОтрезокТекста:-
   выделитьИзФайлаОтрезокТекстаСЗаданнойДлиной(ИмяФайла,ЧислоСимоволов)=ОтрезокТекста:-
Строка 19: Строка 19:
*декларация интерфейса (interface ... end interface)
*декларация интерфейса (interface ... end interface)
*имплементация класса (implement ... end implement)
*имплементация класса (implement ... end implement)
Прежде всего рассмотрим варианты взаимного расположения декларации предиката и его клаузы.
Поэтому первое условие видимости: декларация вызываемого элемента должна быть видна из места вызова.
Рассмотрим следующие программные конструкции
<vip>
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
</vip>
Здесь представлены два класса, порождающих объекты: parent (родитель) и child (потомок)
helloWorldFromChild(...) - подчиняется правилу public
а на
helloWorldFromParent(...) - действует правило protected.
У объекта класса child можно вызвать только предикат
helloWorldFromChild(...), а из объекта класса child можно обратиться как к предикату
helloWorldFromChild(...), так и к предикату helloWorldFromParent(...).
Имя интерфейса является также и именем домена
объединение предикатов нескольких интерфейсов или подмена одного интерфейса другим легко делается с помощью объявления supports, например,
<vip>
interface myInterface
supports myInterface1
supports myInterface2
end interface myInterface
</vip>
Если у Вас есть интерфейсы myInterface1 и myInterface2, то через myInterface можно оперировать предикатами из myInterface1 и myInterface2 как предикатами одного интерфейса. В добавок myInterface тоже может иметь свой список объявлений предикатов.
Кроме того есть такие возможности, как
delegate interface - когда можно передать исполнение предикатов интерфейса объекту, хранящемуся в факте-переменной.
Возможно перекрывать имплементацию предиката(ов) родительского класса имплементацией предиката(ов) дочернего класса, например, родителький класс содержит имплементацию "по умолчанию", а ряд конкретных классов должен реагировать на вызов предикатов особенным образом.
Клаузы для предикаты одного интерфейса могут содержаться в имлементациях разных классов путем использования конструкции
predicates from ...
То есть интерфейс есть фасадная часть класса (динамического), а механизмы имплементации могут быть самыми разными.
Я думаю здесь та же история, что и с типизацией в Turbo, PDC и Visual Прологах: технически оправдано и практически ведет к повышению надежности программ.
1. Ни классы, ни интерфейсы не имеют никаких предопределенных предикатов (кроме конструкторов, относящихся только к декларации класса), а видимость фактов предполагает операции над ними и, cоответственно, наличие предопределенных предикатов.
2. Причина дисциплинарного характера - выполнять операции над фактами только через соответствующие предикаты. Глобальные данные должны храниться в объекте, о котором должны знать те, кому положено.
В имплементации происходит наследование классов (точнее - объектов-экземпляров этих классов), а вот наследуются методы или нет - это определяется интерфейсами, которые эти классы поддерживают. Кроме того, предикаты, объявленные внутри имплементации видны только изнутри только этой имплементации.
Ниже я переименовал классы и интерфейсы, чтобы было яснее где что.
<vip>
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
</vip>
publicPredicate() доступен из класса childClass,а
privatePredicate недоступен для использования нигде,
кроме как в самом классе parentClass.
*Интерфейс никак не зависит от класса - это именованный набор предикатов и/или доменов и/или констант.
*Класс поддерживает некоторый интерфейс (своей имплементацией), если этот интерйес указан в декларации класса.
*Имплементация всегда соответствует классу и имеет с ним одно имя.
*Если класс поддерживает интерфейс, то имплементация должна тем или иным образом привести к клаузу для каждого предиката интерфейса.
Поэтому может быть много разных классов , поддерживающих один и тот же интерфейс.
Статический класс не наследуется - у него нет ни конструктора, ни интерфейса, а они необходимы для работы механизма наследования.
Да, класс может поддерживать некий интерфейс и плюс набор статических сущностей.
В имплементации происходит наследование классов,
а вот наследуются методы или нет - это определяется интерфейсами, которые эти классы поддерживают.
Из иплементации дочернего класса видны все предикаты, декларированные в интерфейсах родительских классов.
При обращении же к дочернему классу видны только предикаты, декларированные в интерфейсе этого дочернего класса.
Рассмотрим пример.
Допустим, есть классы - родители (я опускаю синтаксические детали вроде end class... и похожие)
<vip>
parentClass_1:Interface_1
parentClass_2:Interface_2
</vip>
Имплементации классов parentClass_1 и parentClass_2 поддерживают предикаты, декларированные в интерфейсах Interface1 и Interface2, соответственно.
Допустим, есть дочерний класс childClass:childInterface
Пусть есть интерфейс
<vip>
interface childInterface
supports Interface_1
</vip>
Примечание: для такого случая можно было бы иметь
декларацию класса в виде childClass:Interface_1
Теперь пусть есть имплементация дочернего класса:
<vip>
implement childClass
inherits parentClass_1
inherits parentClass_2
</vip>
Что и откуда можно видеть?
1. из имплемнтации childClass видны (могут быть вызваны):
a) все предикаты, непосредственно декларированные интерфейсе childInterface
B) все предикаты, декларированные интерфейсе Interface_1
с) все предикаты, декларированные интерфейсе Interface_2
2. Из какого-либо класса вне childClass видны (могут быть вызваны) при обращеии к его экземпляру:
a) все предикаты, непосредственно декларированные интерфейсе childInterface
B) все предикаты, декларированные интерфейсе Interface_1
[[Категория:VipLanguage_в_работе]]

Текущая версия на 12:29, 28 сентября 2007

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

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

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

Например, в следущем коде

predicates
  выделитьИзФайлаОтрезокТекстаСЗаданнойДлиной:(string FileName, unsigned ЧислоСимоволов) ->string
clauses
  выделитьИзФайлаОтрезокТекстаСЗаданнойДлиной(ИмяФайла,ЧислоСимоволов)=ОтрезокТекста:-
    ПолныйТекстФайла=прочитатьФайл(ИмяФайла),
    ...

декларация (раздел predicates) и клауза (раздел clauses) помещаются рядом по тексту. Но это лишь частный случай возможного их взаимного размещения. Местом помещения исполнительной части всегда является имплементация класса (implement ... end implement). Местами помещения декларации могут быть:

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