Классы на Ls

Тема в разделе "Lotus - Программирование", создана пользователем VladSh, 13 июл 2010.

  1. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Хоть оно понемножку и отмирает, но... предлагаю делиться в этой теме фишками, областью применения классов на LS.

    Начну) Не факт, что скажу что-то новое, но вдруг кому-то окажется полезным.

    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">1. Наследование "ветвлением" и убогое использование через Variant.</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    Class ClassBase

    Sub New(ND As NotesDocument)
    End Sub

    End Class


    Class ClassUser As ClassBase

    Sub New(ND As NotesDocument)
    End Sub

    Function MyFunction1()
    MessageBox TypeName(Me) & "." & LSI_Info(2)
    End Function

    Sub UserSub()
    MessageBox TypeName(Me) & "." & LSI_Info(2)
    End Sub

    End Class


    Class ClassServer As ClassBase

    Sub New(ND As NotesDocument)
    End Sub

    Function MyFunction1()
    MessageBox TypeName(Me) & "." & LSI_Info(2)
    End Function

    Sub ServerSub()
    MessageBox TypeName(Me) & "." & LSI_Info(2)
    End Sub

    End Class
    Функция-Инициализатор:
    Код (Text):
    Function InitClassObject(ND As NotesDocument) As ClassBase
    Dim CB As ClassBase
    Dim NS As New NotesSession

    'Функция, собственно, и сделана для того, чтобы зашить эти ПРОВЕРКИ (их может быть море) внутрь,
    'а также чтобы программист не думал где и как будет выполняться код, а просто обращался к методам и всё;
    'использовать с помощью данного разделения лишь тот функционал, который нужен в данный момент.
    If NS.IsOnServer Then
    Set CB = New ClassServer(ND)        'Присваивание вполне нормально проходит...
    Else
    Set CB = New ClassUser(ND)          'Присваивание вполне нормально проходит...
    End If

    If Not CB Is Nothing Then       'Для уникумов, которе привыкли пихать в конструктор код, могущий привести к НЕинициализации объекта
    Set InitClassObject = CB
    End If
    End Function
    Ну и вызов с кнопки:
    Код (Text):
    Sub Click(Source As Button)
    Dim ND As NotesDocument
    Dim CB As Variant
    '...
    Set CB = InitClassObject(ND)
    If Not CB Is Nothing Then
    'Variant всё схавает...:
    Call CB.MyFunction1()  
    'Call CB.UserSub()              'Опасно, потому не имеет право на жизнь!
    Delete CB
    End If
    End Sub
    Использование через Variant убогое потому, что:
    - не позволяет отловить ошибки на стадии компиляции;
    - не позволяет пользоваться окошком ShowProperties Domino Designer'а.

    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">2. Наследование "ветвлением" и НОРМАЛЬНОЕ использование через тип базового класса.</div></div><div class="sp-body"><div class="sp-content">Удобно, чтобы писать универсальный код, не задумываясь как и при каких условиях он будет выполняться.
    Главное условие - совпадение (потому чёткое наследование!) Public-методов.


    Немного меняем базовый класс:
    Код (Text):
    Class ClassBase

    Sub New(ND As NotesDocument)
    End Sub

    Public Function MyFunction1()
    Call Me.ShowNoBaseMsg()
    End Function

    Private Sub ShowNoBaseMsg()
    MessageBox "Данный метод " & TypeName(Me) & "." & LSI_Info(12) & " не предназначен для прямого вызова, его необходимо переопределить и вызывать из объекта класса-наследника!", 48, "Ошибка разработчика..."
    End Sub

    End Class
    Код (Text):
    Sub Click(Source As Button)
    Dim ND As NotesDocument
    Dim CB As ClassBase
    '...
    Set CB = InitClassObject(ND)
    If Not CB Is Nothing Then
    Call CB.MyFunction1()           'Объявляли как ClassBase, а пользуемся как классом-наследником, не зная что за наследник!
    'Call CB.UserSub()              'А в этом варианте не прокатит уже на стадии компиляции! Имеет право на жизнь только для Private-методов...
    Delete CB
    End If
    End Sub

    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">3. Последовательное наследование и выполнение части работы методами базового класса.</div></div><div class="sp-body"><div class="sp-content">Удобно, когда базовый класс может работать самостоятельно, а также наследуемый класс использует часть функционала базового.
    Обычно такие классы разносятся по разным библиотекам, чтобы лишний раз не грузить память и каждый раз использовать только тот функционал, что нужен в данный момент.


    Код (Text):
    Class ClassBE

    Sub New()
    End Sub

    Function MyFunction1()
    MessageBox TypeName(Me) & "." & LSI_Info(2)
    End Function

    End Class
    Код (Text):
    Class ClassFE As ClassBE

    Function MyFunction1()
    'Собственная реализация
    MessageBox TypeName(Me) & "." & LSI_Info(2)
    'А также выполнение этого же метода базового класса
    Me.MyFunction1 = ClassBE..MyFunction1()
    End Function

    End Class
    Если в наследующей библиотеке использовать инициализатор, как в предыдущем примере, то дополнительно получаем возможность написания однотипного кода не задумываясь над тем, где и в каких код условиях будет выполяться.

    4. Обязательность конструктора наследуемых классов.
    В предыдущем примере мы видим, что конструктор в классе-наследнике отсуствует... Он обязателен только, если в него передаётся хоть один параметр. Если же нет, то на конструкторе можно сэкономить :)

    5. Динамическое количество параметров в конструкторе.
    Редко используемая, но интересная вещь.
     
  2. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.373
    Симпатии:
    2
    "Ану-ка, давай-ка, плясать выхади!" (с) Ну, погоди!

    Для наглядности приведу тут источник
    <!--QuoteBegin-VladSh+-->
    <span class="vbquote">(VladSh)</span><!--QuoteEBegin-->Намного привлекательней всё это становится, если ещё и менять типы параметров, - это можно сделать через Variant:
    --------------------------
    Код (LotusScript):
    Class CBaseParent

    Sub New(OBJ As Variant, pS As String)
    End Sub

    End Class


    Class CChildeND As CBaseParent

    Sub New(ND As NotesDocument, pS As String), CBaseParent(OBJ, pS)
    End Sub

    End Class


    Class CChildeNDB As CBaseParent

    Sub New(NDB As NotesDatabase, pS As String), CBaseParent(OBJ, pS)
    End Sub

    End Class
    [/quote]

    Внимание вопрос: что передается в конструктор родителя?
    Class CChildeND As CBaseParent
    Sub New(ND As NotesDocument, pS As String), CBaseParent(OBJ, pS)


    Понятно, pS у нас есть одноименный в дочернем конструкторе, его же передадут и родителю, а OBJ - что за зверь? Откуда берется? Вообще, компилятор должен материться, что не определена! О.о
     
  3. fedotxxl

    fedotxxl Well-Known Member

    Регистрация:
    9 ноя 2005
    Сообщения:
    614
    Симпатии:
    0
    Спасибо, не знал... или забыл
     
  4. Darker

    Darker Гость

    а я думал как обычно объявляются необязательные параметры, оказывается вот оно как! Это замечательно! Жаль для методов\функций это не распространяется
     
  5. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.373
    Симпатии:
    2
    Где ты там это увидел?!
     
  6. Darker

    Darker Гость

    Sorry, видать не так понял
    MessageBox ( message [ , [ buttons + icon + default + mode ] [ , boxTitle ] ] )
    думал, речь об этом(только для конструктора)
     
  7. turumbay

    Регистрация:
    13 мар 2009
    Сообщения:
    625
    Симпатии:
    2
    вообще, фактически все паттерны gof, реализуются на ls.
    приватный конструктор: http://codeby.net/ipb.html?s=&sh...st&p=147161
    использование приватного конструктора позволяет, кроме прочего, реализовывать нормальные фабрики классов - без возможности прямого инстанцирования объекта клиентом. эта же конструкция может использоваца для создания перечислений( enumerations ).
     
  8. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Когда использовать из класса-наследника, то всегда передаётся EMPTY.
    Эта штука нужна для возможности хранения логики в CBaseParent вне зависимости от типа базового объекта (тип NotesDatabase неудачно выбран, здесь лучше подошли бы самописные классы...), со всеми вытекающими из Variant... Это плохо, но возможность такая есть.

    Не матерится, и даже работает)))

    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Тогда подробнее (+)</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    Class CBaseParent
    Private m_objBase As Variant

    Sub New(OBJ As Variant, pS As String)
    Call Me.SetBaseObject(OBJ)
    Print TypeName(Me) & "." & LSI_Info(2) & "; TypeName(OBJ)=" & TypeName(OBJ)
    End Sub

    Private Sub SetBaseObject(OBJ As Variant)
    If IsObject(OBJ) Then Set Me.m_objBase = OBJ
    End Sub

    End Class


    Class CChildeNDB As CBaseParent

    Sub New(NDB As NotesDatabase, pS As String), CBaseParent(OBJ, pS)
    Call Me.SetBaseObject(NDB)
    End Sub

    End Class
    И вызов:
    Код (Text):
    Dim CChildeNDB As CChildeNDB
    Dim NS As New NotesSession
    Dim NDB As NotesDatabase

    Set NDB = NS.CurrentDatabase

    Set CChildeNDB = New CChildeNDB(NDB, pS$)
    Так пойдёт? :)
     
  9. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.373
    Симпатии:
    2
    Пипець ))
     
  10. TIA

    TIA :-)
    Lotus team

    Регистрация:
    15 май 2009
    Сообщения:
    790
    Симпатии:
    0
    Господа, про инициализацию конструктора базового класса в любимом хелпе же есть.

    The argument list for the sub New of the base class does not match the argument list for the sub New of the derived class in number and data type of arguments; or you want to pass different arguments to the base class sub New than those passed to the derived class sub New.
     
  11. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.373
    Симпатии:
    2
    TIA
    Я это знаю, меня возмутило именно, что в родительский конструктор, который обязателен, передается непонятная сущность О.о
     
  12. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Akupaka
    В родительском этот параметр описан как Variant, а он всё схавает.
     
  13. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.373
    Симпатии:
    2
    Да не в типе дело, а в ее имени ;)
     
  14. nvyush

    nvyush Lotus team
    Lotus team

    Регистрация:
    22 апр 2009
    Сообщения:
    2.317
    Симпатии:
    0
    Ну, если не стоит Option Declare, то нет проблем.
     
  15. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.373
    Симпатии:
    2
    VladSh, ану-ка, как ты будешь оправдываться? ))
     
  16. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Я, и вдруг буду оправдываться??? То ты меня плохо знаешь! ))

    > Option Declare
    Да я просто не использую эту хрень. Причём никогда.
     
  17. Akupaka

    Akupaka А че я?.. О.о

    Регистрация:
    4 окт 2007
    Сообщения:
    3.373
    Симпатии:
    2
    И этот человек будет мне рассказывать "как плохо использовать связи между объектами"! )))
    Ты вот сразу про это не мог уточнить? Я тут закипел, мир перевернулся, а все оказывается из-за отсутствия опции декларации!
     
  18. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    К связям между объектами Option Declare никак не относится.

    Option Declare не имеет тут ни какого значения.
    Я вставил его, единственное что пришлось сделать - положить в Declarations библиотеки строку
    Код (Text):
    Private OBJ As Variant
    Даже перекомпиливать вызовы не пришлось. Всё работает.
     
  19. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Пятница...

    Разбирали паттерн State. Честно говоря, был удивлён, но для LS всё получилось:
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">код</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    %REM
    Library patternState
    Created Apr 1, 2011 by Владислав Сергеевич Шубников/LISSOFT
    Description: проба паттерна State
    %END REM
    Option Public

    Const MSGP_LN = "Lotus Notes..."
    Const VAR_G1 = "%VAR1%"
    Const MSGP_STATENAME = "Я " + VAR_G1 + " !"    'особо правильные пацаны хранят это в справочнике!


    %REM
    Function localize
    Description: заодно поржём над локализацией и глобализацией)))
    %END REM
    Function localize(pStr As String) As String
    localize = Replace(MSGP_STATENAME, VAR_G1, pStr)
    End Function


    %REM
    Class
    Description: основной класс
    %END REM
    Class Pattern
    Public state As StateBase

    Function Init(pState As StateBase) As Boolean
    Set Me.state = pState
    End Function

    Sub ChangeState()
    Call Me.state.ChangeState(Me)
    MsgBox localize(TypeName(Me.state)), 64, MSGP_LN    'а-я-яй! это плохо вызывать внешние функции из класса!))
    End Sub

    End Class


    %REM
    Class StateBase
    Description: базовый класс для состояний
    %END REM
    Class StateBase

    Public Sub ChangeState(pPattern As Pattern)
    End Sub

    End Class


    Class State1 As StateBase

    Public Sub ChangeState(pPattern As Pattern)
    Dim st As New State2
    Set pPattern.state = st
    End Sub

    End Class


    Class State2 As StateBase

    Public Sub ChangeState(pPattern As Pattern)
    Dim st As New State1
    Set pPattern.state = st
    End Sub

    End Class
    Вызов:
    Код (Text):
    Use "patternState"

    Sub Click(Source As Button)
    Dim pattern As New Pattern
    Dim state As StateBase

    Set state = New State1
    Call pattern.Init(state)
    Call pattern.ChangeState()
    Call pattern.ChangeState()
    End Sub
    Штука получилась бомбовая!
    Основная идея здесь не вбрасывание уже готового состояния извне, не изменение его извне или внутри основного класса, а изменение его изнутри самих классов-состояний, т.е. само состояние, в зависимости от каких-либо условий, может изменить себя или, другими словами состояние объекта может измениться вне его, но ему как бы всё равно...)

    Пока не знаю, где это можно применить... /только игр нам на Лотусе не хватало ;D/
    Друзья, предлагайте! ;)
     
  20. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Псевдо-Reflection - реализуем "вычисляемое имя метода"

    Например, есть<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">класс с кучей методов</div></div><div class="sp-body"><div class="sp-content">
    Код (LotusScript):
    Class MegaClass
    Sub addInteger(value As Integer)
    Print value
    End Sub

    Sub addDouble(value As Double)
    Print value
    End Sub

    Sub addString(value As String)
    Print value
    End Sub
    End Class
    иногда приходится делать такую неприятную штуку, как <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">switch</div></div><div class="sp-body"><div class="sp-content">
    Код (LotusScript):
    Set oMegaClass = ...
    'sTypeName и value передаются откуда-то извне
    Select Case sTypeName
    Case "Double":
    Call oMegaClass.addDouble(value)
    Case "Integer":
    Call oMegaClass.addInteger(value)
    Case "String":
    Call oMegaClass.addString(value)
    Case "...":
    '...
    End Select
    Хотелось бы получать параметры и типы извне и производить добавление, как-то в цикле - одной строкой..
    Можно вытворить "рефлексию" и на LS, правда от использования Variant уйти удалось не совсем.

    Создаём интерфейс, унифицирующий имя метода, и клепаем от него классы, обрабатывающие соответствующий тип:
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Интерфейс и его классы-наследники</div></div><div class="sp-body"><div class="sp-content">
    Код (LotusScript):
    %REM
    Class IReflectionMegaClass
    Description: класс-интерфейс для наследников
    %END REM

    Class IReflectionMegaClass
    Private oMegaClass As MegaClass

    Sub New(oMegaClass As MegaClass)
    Set Me.oMegaClass = oMegaClass
    End Sub

    Public Sub add(value As Variant)
    End Sub
    End Class

    %REM
    Class ReflectionMegaClassDouble
    Description: организует перенаправление на метод, работающий с Double
    %END REM

    Class ReflectionMegaClassDouble As IReflectionMegaClass
    Sub New(oMegaClass As MegaClass)
    End Sub

    Public Sub add(value As Variant)
    Call Me.oMegaClass.addDouble(CDbl(value))
    End Sub
    End Class

    %REM
    Class ReflectionMegaClassInteger
    Description: организует перенаправление на метод, работающий с Integer
    %END REM

    Class ReflectionMegaClassInteger As IReflectionMegaClass
    Sub New(oMegaClass As MegaClass)
    End Sub

    Public Sub add(value As Variant)
    Call Me.oMegaClass.addInteger(CInt(value))
    End Sub
    End Class

    %REM
    Class ReflectionMegaClassString
    Description: организует перенаправление на метод, работающий со String
    %END REM

    Class ReflectionMegaClassString As IReflectionMegaClass
    Sub New(oMegaClass As MegaClass)
    End Sub

    Public Sub add(value As Variant)
    Call Me.oMegaClass.addString(CStr(value))
    End Sub
    End Class
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Класс-"обёртка" над этими классами-"типами", использующаяся снаружи</div></div><div class="sp-body"><div class="sp-content">
    Код (LotusScript):
    %REM
    Class PseudoReflection
    Description: работа с классом по типу обрабатываемой им переменной
    %END REM

    Class PseudoReflection
    'список всех объектов, реализующих поведение метода add в соответствии с типом
    Private lstTypeObjects List As IReflectionMegaClass

    %REM
    Sub New
    Description: инициализируем все типы сразу
    %END REM

    Sub New()
    Dim oMegaClass As New MegaClass()   'в принципе тоже можно передать параметром
    Set Me.lstTypeObjects("Double") = New ReflectionMegaClassDouble(oMegaClass)
    Set Me.lstTypeObjects("Integer") = New ReflectionMegaClassInteger(oMegaClass)
    Set Me.lstTypeObjects("String") = New ReflectionMegaClassString(oMegaClass)
    End Sub

    %REM
    Function getTypeObject
    Description: возвращает наружу нужный объект по имени типа
    %END REM

    Public Function getTypeObject(tag As String) As IReflectionMegaClass
    Set Me.getTypeObject = Me.lstTypeObjects(tag)
    End Function

    End Class
    Ну и код использования:
    Код (LotusScript):
    Dim oReflection As New PseudoReflection
    Call oReflection.getTypeObject("Double").add(56342.56869999)
    Call oReflection.getTypeObject("Integer").add(21213)
    Call oReflection.getTypeObject("String").add({Hello, LS-"reflection"!})

    'использование в цикле, к которому мы через такие тернии стремились:
    For ...
    Call oReflection.getTypeObject(sTypeNameVariable).add(valueVariable)
    Next
    P.S. Удобно пользоваться при обработке больших объёмов данных; чем больше будет методов (в данном случае типов), тем больше будет выигрыш в скорости.

    На Java, конечно, всё было бы гораздо проще)
     
Загрузка...
Похожие Темы - Классы на
  1. 203
    Ответов:
    11
    Просмотров:
    2.578
  2. vladis222
    Ответов:
    4
    Просмотров:
    1.649
  3. BashOrgRu
    Ответов:
    6
    Просмотров:
    4.143
  4. Azgor
    Ответов:
    2
    Просмотров:
    1.675
  5. slavon-x86
    Ответов:
    1
    Просмотров:
    3.026

Поделиться этой страницей