Переключение на Главную Страницу Страницы: 1 ОтправитьПечать
Обычная тема Сериализация и наследование (число прочтений - 5926 )
kos
Full Member
***
Отсутствует


1C++ rocks!

Сообщений: 127
Местоположение: Киев
Зарегистрирован: 03. Марта 2013
Сериализация и наследование
17. Августа 2013 :: 13:54
Печать  
Прочитал статьи
http://www.1cpp.ru/forum/YaBB.pl?num=1148469686
http://www.1cpp.ru/bugs/show_bug.cgi?id=1821
http://www.1cpp.ru/forum/YaBB.pl?num=1212044576

В результате уважаемые kms и artbear
пришли к выводу что наследование методов сериализации не нужно

КлассСохраняемый / IsSerializable
СохранитьКлассВСтроку / SaveToString
ЗагрузитьИзСтроки / LoadFromString

Позволю себе НЕ согласиться.

Аргумет первый (теоретический, ООП)

По поводу сериализации:
kms писал(а) 24. Мая 2006 :: 20:02:
С остальными возможны подводные камни, рассмотри:
  • КлассСохраняемый
  • СохранитьКлассВСтроку
  • ЗагрузитьИзСтроки (добавь себе в список, кстати)
    .......skip....
    Думаю, эти методы не нужно наследовать.Это функции типа конструктора/деструктора - индивидуальные для класса.


  • По поводу конструкторов:
    artbear писал(а) 25. Мая 2006 :: 13:40:
    kms писал(а) 24. Мая 2006 :: 20:02:
    Кстати, напомните мне, в 1cpp при создании объекта-наследника конструкторы базовых классов выполняются или нет?
    Если да, то в каком порядке?


    Конечно, вызываются - это основа ООП.
    Добавил соответствующий юнит-тест в конфу тестирования 1С++.

    Порядок вызова соответствует порядку объявления предков.


    НО!! Восстановление объекта при сериализации = по своей сути = это ТОТ ЖЕ конструктор, только вот такой:
    ADirks писал(а) 29. Мая 2008 :: 09:18:
    Нормальная сериализация - это безусловно хорошо  Улыбка

    Про конструктор: думаю, что конструктор вызывать не надо. Сериализуемый объект должен сам знать, как ему восстановиться из строки. Конструктор - он ведь в основном нужен для установки начальных значений внутренних переменных, так? Если же в конструкторе выполняются какие-то странные действия - то кто нам мешает выполнить (или не выполнить) их при десериализации?
    Десериализация это не штатное создание объекта. При десериализации объект возникает сразу и взрослым, а не проходит все стадии развития.


    В результате всего этого (а также других размышлений в указанных статьях уважаемых ADirks, kms, artbear)
    я предлагаю посмотреть на сериализацию (с точки срения ООП) так:
    1) наследование "обычных" конструкторов - выполняется (если они объявлены как "ЭКСПОРТ", проверено)
    2) сохранение/восстановление КОП = это аналог вызова конструктора с параметром (для создания "только взрослый объект сразу")

    Значит, наследование при сериализации должно отрабатывать ТАК ЖЕ как и обычный конструктор:
    *  сперва сериализация по каждому из предков в порядке объявления в DEFCLS
    *  если в предках таких методов нет или они без "ЭКСПОРТ" из наследника они (естественно) не вызываются (не наследуются)
    *  затем отрабатывает сериализация текущего класса-наследника
    *  сериализация в классе отрабатывает ТОЛЬКО при наличии ВСЕХ трех методов (не важно - реализованы в этом классе или унаследованы от предка)

    P.S> боязнь конфликтов PRIVATE-переменных:
    - их должны восстанавливать методы предка, которые должны вызываться из наследника
    - разработчик класса САМ должен позаботиться о логике сохранения/восстановления объекта (если "криво" - получит исключение)

    Аргумет второй (практический пример)

    Есть иерархия

    Код
    Выбрать все
    //класс Расширитель1С          = Расширитель1С.ert {};
    //класс Справочник               = Справочник.ert   : Расширитель1С, Reference {};
    //класс Справочник.Товары   = Справочник.Товары.ert   : Справочник, Reference.Товары {};
    //класс Справочник.Клиенты = Справочник.Клиенты.ert   : Справочник, Reference.Клиенты {};
    //класс Документ               = Документ.ert   : Расширитель1С, Document {};
    //класс Документ.Накладная  = Документ.Накладная.ert   : Документ, Document.Накладная {}; 
    
    


    Методы класса "Расширитель1С":

    Код
    Выбрать все
    // виртуальный метод, обязан быть переопределен наследником:
    функция ИмяБазовогоОбъекта1с() Экспорт
       возврат ""
    КонецФункции    
    
    // каждый из следующих методов может быть переопределен в наследниках,
    // но не обязательно: базовый функционал остается здесь....
    
    Функция ПолучитьБазовыйОбъект() Экспорт
       // вернет нативный объект 1С типа "Reference.XXX / Document.XXX / ...."
       возврат _Хелпер._ПолучитьБазу(вирт(),вирт().ИмяБазовогоОбъекта1с())
    КонецФункции
    
    Функция УстановитьБазовыйОбъект(Объект) Экспорт
       // здесь "Объект" - нативный объект 1С типа "Reference.XXX / Document.XXX / ...."
       // или КОП-наследник от них
       // вернет "Reference.XXX / Document.XXX / ...." или 0
       возврат _Хелпер._УстановитьБазу(вирт(),вирт().ИмяБазовогоОбъекта1с(),Объект)
    КонецФункции
    
    Функция IsSerializable() Экспорт
       возврат 1;
    КонецФункции
    
    Функция SaveToString() Экспорт
       возврат ЗначениеВСтрокуВнутр(вирт().ПолучитьБазовыйОбъект())
    КонецФункции
    
    Процедура LoadFromString(СтрВнутр) Экспорт
       // здесь "СтрВнутр" соотвествует нативному объекту 1С типа "Reference.XXX / Document.XXX / ...."
       вирт().УстановитьБазовыйОбъект(ЗначениеИзСтрокиВнутр(СтрВнутр))
    КонецПроцедуры 
    
    


    Методы класса "Справочник":
    Код
    Выбрать все
    функция ИмяБазовогоОбъекта1с() Экспорт
       возврат "Reference"
    КонецФункции
    Функция SaveToString() Экспорт
       возврат ЗначениеВСтрокуВнутр(вирт().ПолучитьБазовыйОбъект().ТекущийЭлемент())
    КонецФункции
    // остальные методы не переопределяем 
    
    


    Методы класса "Справочник.Товары":
    [code]функция ИмяБазовогоОбъекта1с() Экспорт
      возврат "Reference.Товары"
    КонецФункции
    // остальные методы не переопределя
    « Последняя редакция: 19. Августа 2013 :: 09:04 - kos »  
    Наверх
     
    IP записан
     
    kos
    Full Member
    ***
    Отсутствует


    1C++ rocks!

    Сообщений: 127
    Местоположение: Киев
    Зарегистрирован: 03. Марта 2013
    Re: Сериализация и наследование
    Ответ #1 - 17. Августа 2013 :: 16:07
    Печать  
    Хотя, рассматривать методы сериализации (их поведение) как конструкторы:
    наверное я погарячился..... (в том смысле что вызывать методы предка "автоматом", как конструкторы)

    поведение методов сериализации должно быть

    А) атомарным: в некотором предке должны быть реализованы (можно "пустышкой", виртуальные методы)
     все 3 интерфейса (иначе - ни одного, сериализация не используется)

    Б) если хотим наследовать сериализацию:
     все 3 метода в предке должны быть объявлены как ЭКСПОРТ
     (иначе все - приватные, без ЭКСПОРТ)

    В) в наследнике (если нужно) можно переопределить как 1 так и все 3 метода предка
     те, что НЕ были переопределены - берем из предка

    Г) наследник должен переопределять методы предка (ЭКСПОРТ-ные)
      с директивой ЭКСПОРТ

    Д) если наследник переопределяет методы предка без ЭКСПОРТ
      - то он должен переопределить ВСЕ 3 МЕТОДА, и все - без этой директивы.

    Е) если нужно вызвать метод предка - вызываем его через
    "я().ПолучитьБазовыйКласс(ИмяПредка).ИмяМетода()"
      т.е. как обычно....

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

    При этом:

    1) логика сохранения/восстановления объекта
    должна быть отдана на откуп ПРИКЛАДНОМУ программисту.
    И если он там "напортачил" с доступом к приватным переменным,
    то это проблема прикладного решения а не 1С++ (которое реализует принципы ООП).

    2) В случае ошибки доступа к приватным переменным:
    должно быть вызвано исключение:
    "память не может быть read/write...."
    "в классе Х нет атрибута Y..."
    или что-то вроде этого.....
    (ошибка проектирования)...

    3) В случае "неатомарности" - сообщение (то же что выводится сейчас):
    что-то вроде "Реализованы не все методы в таком-то классе ....."
    и сериализация в этом классе должна отключаться......
    Или тоже исключение (ошибка проектирования)...

    Как-то так.

    artbear писал(а) 24. Мая 2006 :: 13:49:
    В общем, у каждого КОП возможно описать методы, которые пока не наследуются.
    Это
    • _ПолучитьКод
    • КлассСохраняемый
    • СохранитьКлассВСтроку
    • ЗагрузитьИзСтроки
    • _ПолучитьКолвоДСвойств
    • _ПолучитьИмяДСвойства
    • _ПриЧтенииСвойства
    • _ПриЗаписиСвойства
    • ПриЗаписи_ИмяАтрибута
    • ПриПолучении_ИмяАтрибута
    • ОбработкаСобытияОтКласса

    Для каких методов, по-вашему, необходимо наследование?


    Думаю, такое же поведение наследования должно быть и у других методов....

    -------------------------------------------------------------------------------
    ОБЩИЙ ПРИНЦИП НАСЛЕДОВАНИЯ
    ДОЛЖЕН СОБЛЮДАТЬСЯ БЕЗ ИСКЛЮЧЕНИЙ
    ДЛЯ ВСЕХ МЕТОДОВ ВСЕХ ОБЪЕКТОВ (КЛАССОВ).
    -------------------------------------------------------------------------------

    В противном случае:
    возможны варианты
    когда придется
    "копипастить" методы из класса в класс
    а это уже не ООП......


    главное помнить прикладному программисту о методах:
    * вирт()
    * я()
    * я().ПолучитьБазовыйКласс(ИмяПредка)
    * экпортный атрибут/метод или нет - у класса, к которому обращаемся....


    ВОПРОС:

    Уважаемые авторы 1С++, можно ли ждать поправки в конституцию ?
    Т.е. следующего релиза?

    Зарегил в багзиле:
    http://www.1cpp.ru/bugs/show_bug.cgi?id=4562
    « Последняя редакция: 18. Августа 2013 :: 07:18 - kos »  
    Наверх
     
    IP записан
     
    Переключение на Главную Страницу Страницы: 1
    ОтправитьПечать