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

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

 
(не показано 5 промежуточных версий 2 участников)
Строка 1: Строка 1:
Каждый класс должен иметь декларацию класса и имлементацию. Декларация класса содержит набор объявлений констант, доменов, предикатов.  
==Классы==
Имплементация класса содержит собственно реализацию предикатов (клаузы).  
Каждый класс должен иметь декларацию класса и имплементацию.
 
'''Декларация класса''' содержит набор объявлений констант, доменов, предикатов, видимых извне.
 
'''Имплементация класса''' содержит  
*собственно реализацию предикатов (клаузы), объявленных в декларации,
*декларации констант,
*декларации и реализации предикатов, используемых в клаузах,
*декларации фактов.
*Факты и предикаты, объявленные в имплементации класса, извне не видны.


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


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


Статический класс - это класс, не имеющий интерфейса.  
'''Статический класс''' - это класс, не имеющий интерфейса.  
Или, что то же самое, - если класс не имеет инерфейса, то он - статический,  
Или, что то же самое, - если класс не имеет инерфейса, то он - статический,  


Если класс имеет интерфейс - то он - динамический.  
Если класс имеет интерфейс - то он - динамический.  


Статические классы  
==Статические классы==
Например, класс staticClass является статическим классом.  
Например, класс ''staticClass'' является статическим классом.  
 
<vip>
<vip>
class staticClass
class staticClass
Строка 27: Строка 37:
Чтобы что-то делать, добавим в этот класс декларации предикатов и клаузы.  
Чтобы что-то делать, добавим в этот класс декларации предикатов и клаузы.  


<vip>
<vip>class staticClass
class staticClass
predicates
predicates
   visibleStaticPred:().
   visibleStaticPred:().
end class staticClass
end class staticClass


implement staticClass
implement staticClass
clauses
clauses
     visibleStaticPred():-
     visibleStaticPred():-
       ...
       ...
Строка 40: Строка 49:
       ...         
       ...         


class predicates
class predicates
   invisibleStaticPred:().
   invisibleStaticPred:().
clauses
clauses
   invisibleStaticPred():-
   invisibleStaticPred():-
       ...
       ...
Строка 49: Строка 58:
Обращения к предикатам этого класса записываются как  
Обращения к предикатам этого класса записываются как  


<vip>
<vip>...
...
staticClass::staticVisiblePred(),
staticClass::staticVisiblePred(),
...
  ...
</vip>
</vip>
(существенно использования именно :: для обращения к статической сущности)  
(существенно использования именно '''::''' для обращения к статической сущности)  


Здесь предикат ''invisibleStaticPred'' является предикатом, объявленным внутри имплементации, и только внутри этой имплементации может быть вызван.  
Здесь предикат ''invisibleStaticPred'' является предикатом, объявленным внутри имплементации, и только внутри этой имплементации может быть вызван.  
То есть предикаты, объявленные в декларации класса являются заведомо всегда статическими предикатами, а раздел объявлений предикатов внутри имплементации статического класса всегда должен имет вид  
То есть предикаты, объявленные в декларации класса, являются заведомо всегда статическими предикатами, а раздел объявлений предикатов внутри имплементации статического класса всегда должен имет вид class predicates  
<vip>
Если попробовать создать экземпляр класса ''staticClass'' с помощью вызова конструктора ''new()''
class predicates  
<vip>...
</vip>
staticClass::new(),
Разделы фактов могут быть только в имплементации и для статичесих классов это объявление тоже использует форму
...</vip>
<vip>
class facts
</vip>
Если попробовать создать экземпляр класса ''staticClass'' с помощью вызова конструктора ''new()''  
 
<vip> ...
staticClass::new(),
  ...
</vip>
то это не пропустит компилятор.  
то это не пропустит компилятор.  
Таким образом, статические классы - это просто модули проекта.  
Таким образом, статические классы - это просто модули проекта.  
Проект, построенный только на модулях (статических классах) - не имеет никакого отношения к объекто-ориентированной концепции программирования.  
Проект, построенный только на модулях (статических классах) - не имеет никакого отношения к объекто-ориентированной концепции программирования.  


Динамические классы  
==Динамические классы==
Например, класс ''dynamicClass'' является динамическим классом, что определяется  
Например, класс ''dynamicClass'' является динамическим классом, что определяется  
конструкцией ''dynamicClass:justInterface''.  
конструкцией ''dynamicClass:justInterface''.  
<vip>
<vip>class dynamicClass:justInterface
class dynamicClass:justInterface
end class dynamicClass  
end class dynamicClass  


Строка 87: Строка 84:


interface justInterface
interface justInterface
end interface justInterface
end interface justInterface</vip>
</vip>
Опять-таки, синтаксически все правильно, но практически бесполезно.  
Опять-таки, синтаксически все правильно, но практически бесполезно.  
Теперь добавим какие-нибудь полезности и вынесем вперед декларацию интерфейса.  
Теперь добавим какие-нибудь полезности и вынесем вперед декларацию интерфейса.  
<vip>interface justInterface
<vip>interface justInterface
predicates
predicates
   visibleDynamicPred:().
   visibleDynamicPred:().
end interface justInterface
end interface justInterface


class dynamicClass:justInterface
class dynamicClass:justInterface
predicates
predicates
   visibleStaticPred:().
   visibleStaticPred:().
end class dynamicClass  
end class dynamicClass  


implement dynamicClass  
implement dynamicClass  
clauses
clauses
   visibleStaticPred():-
   visibleStaticPred():-
       ...
       ...
Строка 108: Строка 104:
       ...         
       ...         


clauses
clauses
   visibleDynamicPred():-
   visibleDynamicPred():-
     ...
     ...
Строка 114: Строка 110:
     ...         
     ...         


class predicates
class predicates
   invisibleStaticPred:().
   invisibleStaticPred:().
clauses
clauses
   invisibleStaticPred():-
   invisibleStaticPred():-
       ...
       ...


predicates
predicates
   invisibleDynamicPred:().
   invisibleDynamicPred:().
clauses
clauses
   invisibleDynamicPred():-
   invisibleDynamicPred():-
       ...
       ...
Строка 128: Строка 124:
end implement dynamicClass
end implement dynamicClass
</vip>
</vip>
Здесь мы имеем четыре предиката, которые имеют различные динамические особенности.  
Здесь мы имеем четыре предиката, которые имеют различные динамические особенности.
 
''visibleDynamicPred'' - динамический предикат, принадлежащий интерфесу ''justInterface'', видимый извне.  
''visibleDynamicPred'' - динамический предикат, принадлежащий интерфесу ''justInterface'', видимый извне.  
''visibleStaticPred'' - статический предикат, видимый извне.  
''visibleStaticPred'' - статический предикат, видимый извне.  
''invisibleStaticPred'' - статический предикат, определенный в имплементации класса ''dynamicClass'', невидимый извне.  
''invisibleStaticPred'' - статический предикат, определенный в имплементации класса ''dynamicClass'', невидимый извне.  
''invisibleDynamicPred'' - динамический предикат, определенный в имплементации класса ''dynamicClass'', невидимый извне.  
''invisibleDynamicPred'' - динамический предикат, определенный в имплементации класса ''dynamicClass'', невидимый извне.  
К такому классу можно обратиться как к статическому
<vip>...
dynamicClass::visibleStaticPred(),
...</vip>
но нельзя так:
<vip>...
dynamicClass::visibleDynamicPred(),
...</vip>
Чтобы вызвать предикат ''visibleDynamicPred()'', необходимо с помощью конструктора создать экземпляр класса и обратиться к этому экземпляру:
<vip>...
ЭкземплярDynamicClass=dynamicClass::new(),
ЭкземплярDynamicClass:visibleDynamicPred(),
...</vip>
Примечания:
* Конструктор ''new()'' является предопределенным конструктором, объявление которого не требуется, если в имплементации нет для него клауза;
* В обращении к экземпляру класса (объекту) используется разделитель ':' (а не '::', как этого требует обращение к статической сущности).


Похожим образом внутри имплементации декларируются статические и динамические разделы фактов.  
==Факты==
Факты декларируются и могут быть использованы в клаузах предикатов только в имплементации класса.
Нельзя объявить факты в одном классе и пытаться использовать обращение к ним в другом классе.
В статических классах факты должны быть объявлены только как статические.


К такому классу можно обратиться как к статическому
<vip>implement example
...
class facts
  myFact_F:(string,string).
...
end implement example</vip>
В имплементациях динамических классов факты могут быть объявлены либо как статические, либо как динамические:
<vip>class example1:example1interface
predicates
  запомнитьГород:(string Город).
  запомнитьИмяАдрес:(string Имя, string Адрес).
  получитьГород:()->string Город.
  получитьИмяАдрес:(string Имя, string Адрес).
end class example1
 
implement example1
...
class facts
  город_V:string Город.
...
facts
  имяАдрес_F:(string Адрес, string Имя).
 
clauses
  запомнитьГород(Город):-
    город_V:=Город.
...
clauses
  запомнитьИмяАдрес(Имя,Адрес):-
    assert(имяАдрес_F:(Адрес,Имя)).


<vip>    ...
clauses
     dynamicClass::visibleStaticPred(),
  получитьГород(город_V).
  ...
clauses
  получитьИмяАдрес(Имя,Адрес):-
     имяАдрес_F(Адрес,Имя),
    !,
     ...
     ...
end implement example1
</vip>
В приведенном примере класса ''example1'' факт ''город_V'' является статическим, а факты ''имяАдрес_F(...)'' являются динамическими,
что определяется разницей в имени раздела ''class facts'' и просто ''facts''.
Поскольку статическая сущность любого класса всего одна, а динамическая - по одной на каждый экземпляр - то и в нашем примере запрос ''получитьГород()'', переданный любому экземпляру, вернет один и тот же результат, а запрос ''получитьИмяАдрес(...)'' вернет для каждого экземпляра свое значение.
===Особенности использования фактов-переменных===
В примере выше использовался факт-переменная ''город_V'', особенностью которого является то, что такой факт всегда один и он сам несет значение терма, объявленного в декларации.
<vip>
class facts
  город_V:string Город.</vip>
Здесь факт ''город_V'' имеет строковое значение. Возможны значения любых объявленных доменов, например
<vip>domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  персона_V:мойДомен.</vip>
В отличие от обычных фактов, факт-переменная всегда существует и должен иметь начальное значение.
Начальное значение факту-переменной можно задать при объявлении
<vip>domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  персона_V:мойДомен:=персона("Старик",80).
  город_V:string:="НеИзвестен".
</vip>
</vip>
но нельзя так:  
В динамических классах начальное значение вместо декларации можно задать в клаузе конструктора
<vip>implement dynamicClass
domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  персона_V:мойДомен.
clauses
  new():-
    персона_V:=персона("Старик",80),
    ...
end implement dynamicClass</vip>
Бывает, что конкретное начальное значение установить невозможно по смыслу реализации.
Тогда начальное значение может быть установлено как "неустановленное".
<vip>class facts
  город_V:string:=erroneous.</vip>
где ''erroneous'' - ключевое слово языка. Факт со значением erroneous не может быть использован (точнее: при попытке его использования будет выдана соответствующая ошибка), можно только проверить является ли значение факта неустановленным с помощью детерминированного предиката ''isErroneous(...)''
<vip>implement dynamicClass
domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  город_V:string:=erroneous.
  персона_V:мойДомен.
clauses
  new():-
    персона_V:=персона("Старик",80),
    ...
clauses
  ...
    isErroneous(город_V),
    ...
end implement dynamicClass</vip>
С учетом сказанного наш пример
<vip>class facts
  город_V:string Город.</vip>
на этапе компиляции выдаст ошибку, поскольку статический факт не инициализирован при объявлении.
 
==Константы и домены==
Константы и домены могут объявляться везде - в декларациях классов, интерфейсов и в имплементациях. По своей сущности они, естественно, имеют статический характер.
Объявления, сделанные в имплементации, видимы только внутри этой же имплементации.
Объявления констант и доменов, сделанные в декларации класса или интерфейса, являются глобальными.
Конкретное использование осуществляется путем добавления префикса декларации соответствующего класса или интерфейса в формате
 
''<имя декларации класса или интерфейса>::<имя домена или константы>''.


<vip>   ...
==Взаимоотношени статических и динамических сущностей==
    dynamicClass::visibleDynamicPred(),
Клаузы предикатов, объявленных статическими, не могут обращаться к динамическим сущностям (предикатам и фактам).
То есть нельзя так:
<vip>implement dynamicClass
clauses
  staticPred():-
     ...
     ...
</vip>
     dynamicPred(),
Чтобы вызвать предикат ''visibleDynamicPred()'', необходимо с помощью конструктора создать
экземпляр класса и обратиться к этому экземпляру:
 
<vip>    ...
     ЭкземплярDynamicClass=DynamicClass::new(),
    ЭкземплярDynamicClass:visibleDynamicPred(),
     ...
     ...
</vip>
end implement dynamicClass</vip>
Примечания:
Клаузы предикатов, объявленных динамическими, такого ограничения не имеют.
a) Конструктор ''new()'' является предопределенным конструктором, объявление которого не требуется;
Как статические так и динамические факты могут хранить указатели на динамические предикаты и экземпляры классов.
B) В обращении к экземпляру класса (объекту) используется разделитель '''':'''' (а не '::', как этого требует обращение к статической сущности);
[[Категория:VipLanguage]]
[[Категория:VipLanguage]]

Текущая версия на 09:43, 8 августа 2008

Классы

Каждый класс должен иметь декларацию класса и имплементацию.

Декларация класса содержит набор объявлений констант, доменов, предикатов, видимых извне.

Имплементация класса содержит

  • собственно реализацию предикатов (клаузы), объявленных в декларации,
  • декларации констант,
  • декларации и реализации предикатов, используемых в клаузах,
  • декларации фактов.
  • Факты и предикаты, объявленные в имплементации класса, извне не видны.

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

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

Статический класс - это класс, не имеющий интерфейса. Или, что то же самое, - если класс не имеет инерфейса, то он - статический,

Если класс имеет интерфейс - то он - динамический.

Статические классы

Например, класс staticClass является статическим классом.

class staticClass
end class staticClass
 
implement staticClass
end implement staticClass

но этот класс ничего не способен делать. Чтобы что-то делать, добавим в этот класс декларации предикатов и клаузы.

class staticClass
predicates
   visibleStaticPred:().
end class staticClass
 
implement staticClass
clauses
     visibleStaticPred():-
       ...
       invisibleStaticPred(),
       ...         
 
class predicates
   invisibleStaticPred:().
clauses
   invisibleStaticPred():-
       ...
end implement staticClass

Обращения к предикатам этого класса записываются как

...
staticClass::staticVisiblePred(),
...

(существенно использования именно :: для обращения к статической сущности)

Здесь предикат invisibleStaticPred является предикатом, объявленным внутри имплементации, и только внутри этой имплементации может быть вызван. То есть предикаты, объявленные в декларации класса, являются заведомо всегда статическими предикатами, а раздел объявлений предикатов внутри имплементации статического класса всегда должен имет вид class predicates Если попробовать создать экземпляр класса staticClass с помощью вызова конструктора new()

...
staticClass::new(),
...

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

Динамические классы

Например, класс dynamicClass является динамическим классом, что определяется конструкцией dynamicClass:justInterface.

class dynamicClass:justInterface
end class dynamicClass 
 
implement dynamicClass 
end implement dynamicClass 
 
interface justInterface
end interface justInterface

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

interface justInterface
predicates
   visibleDynamicPred:().
end interface justInterface
 
class dynamicClass:justInterface
predicates
   visibleStaticPred:().
end class dynamicClass 
 
implement dynamicClass 
clauses
   visibleStaticPred():-
      ...
      invisibleStaticPred(),
      ...         
 
clauses
   visibleDynamicPred():-
     ...
     invisibleStaticPred(),
     ...         
 
class predicates
   invisibleStaticPred:().
clauses
   invisibleStaticPred():-
       ...
 
predicates
   invisibleDynamicPred:().
clauses
   invisibleDynamicPred():-
       ...
 
end implement dynamicClass

Здесь мы имеем четыре предиката, которые имеют различные динамические особенности. visibleDynamicPred - динамический предикат, принадлежащий интерфесу justInterface, видимый извне. visibleStaticPred - статический предикат, видимый извне. invisibleStaticPred - статический предикат, определенный в имплементации класса dynamicClass, невидимый извне. invisibleDynamicPred - динамический предикат, определенный в имплементации класса dynamicClass, невидимый извне. К такому классу можно обратиться как к статическому

...
dynamicClass::visibleStaticPred(),
...

но нельзя так:

...
dynamicClass::visibleDynamicPred(),
...

Чтобы вызвать предикат visibleDynamicPred(), необходимо с помощью конструктора создать экземпляр класса и обратиться к этому экземпляру:

...
ЭкземплярDynamicClass=dynamicClass::new(),
ЭкземплярDynamicClass:visibleDynamicPred(),
...

Примечания:

  • Конструктор new() является предопределенным конструктором, объявление которого не требуется, если в имплементации нет для него клауза;
  • В обращении к экземпляру класса (объекту) используется разделитель ':' (а не '::', как этого требует обращение к статической сущности).

Факты

Факты декларируются и могут быть использованы в клаузах предикатов только в имплементации класса. Нельзя объявить факты в одном классе и пытаться использовать обращение к ним в другом классе. В статических классах факты должны быть объявлены только как статические.

implement example
...
class facts
  myFact_F:(string,string).
...
end implement example

В имплементациях динамических классов факты могут быть объявлены либо как статические, либо как динамические:

class example1:example1interface
predicates
  запомнитьГород:(string Город).
  запомнитьИмяАдрес:(string Имя, string Адрес).
  получитьГород:()->string Город.
  получитьИмяАдрес:(string Имя, string Адрес).
end class example1
 
implement example1
...
class facts
  город_V:string Город.
...
facts
  имяАдрес_F:(string Адрес, string Имя).
 
clauses
  запомнитьГород(Город):-
    город_V:=Город.
...
clauses
  запомнитьИмяАдрес(Имя,Адрес):-
    assert(имяАдрес_F:(Адрес,Имя)).
 
clauses
  получитьГород(город_V).
  ...
clauses
  получитьИмяАдрес(Имя,Адрес):-
    имяАдрес_F(Адрес,Имя),
    !,
    ...
end implement example1

В приведенном примере класса example1 факт город_V является статическим, а факты имяАдрес_F(...) являются динамическими, что определяется разницей в имени раздела class facts и просто facts. Поскольку статическая сущность любого класса всего одна, а динамическая - по одной на каждый экземпляр - то и в нашем примере запрос получитьГород(), переданный любому экземпляру, вернет один и тот же результат, а запрос получитьИмяАдрес(...) вернет для каждого экземпляра свое значение.

Особенности использования фактов-переменных

В примере выше использовался факт-переменная город_V, особенностью которого является то, что такой факт всегда один и он сам несет значение терма, объявленного в декларации.

class facts
  город_V:string Город.

Здесь факт город_V имеет строковое значение. Возможны значения любых объявленных доменов, например

domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  персона_V:мойДомен.

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

domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  персона_V:мойДомен:=персона("Старик",80).
  город_V:string:="НеИзвестен".

В динамических классах начальное значение вместо декларации можно задать в клаузе конструктора

implement dynamicClass 
domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  персона_V:мойДомен.
clauses
  new():-
     персона_V:=персона("Старик",80),
     ...
end implement dynamicClass

Бывает, что конкретное начальное значение установить невозможно по смыслу реализации. Тогда начальное значение может быть установлено как "неустановленное".

class facts
  город_V:string:=erroneous.

где erroneous - ключевое слово языка. Факт со значением erroneous не может быть использован (точнее: при попытке его использования будет выдана соответствующая ошибка), можно только проверить является ли значение факта неустановленным с помощью детерминированного предиката isErroneous(...)

implement dynamicClass 
domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  город_V:string:=erroneous.
  персона_V:мойДомен.
clauses
  new():-
     персона_V:=персона("Старик",80),
     ...
clauses
  ...
     isErroneous(город_V),
     ...
end implement dynamicClass

С учетом сказанного наш пример

class facts
  город_V:string Город.

на этапе компиляции выдаст ошибку, поскольку статический факт не инициализирован при объявлении.

Константы и домены

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

<имя декларации класса или интерфейса>::<имя домена или константы>.

Взаимоотношени статических и динамических сущностей

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

implement dynamicClass 
clauses
  staticPred():-
    ...
    dynamicPred(),
    ...
end implement dynamicClass

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