OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 19 Март, 2024 05:04

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 32 ]  На страницу 1, 2  След.
Автор Сообщение
СообщениеДобавлено: Среда, 24 Апрель, 2013 16:31 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2935
Откуда: г. Ярославль
Мёссенбок пишет, что конструктор - это "порождающий паттерн" (Приёмы проектирования в Обероне-2 и Компонентном Паскале):
Цитата:
При создании объекта желательно инициализировать его поля. Если вы не желаете забыть об инициализации, разумно будет объединить создание и определение в одно действие. Для этого и существует шаблон "конструктор"

Можно ли данную процедуру назвать конструктором?

Код:
TYPE
   DropValue* = POINTER TO RECORD (Value)
      val*: Dialog.List;
      data: ListsMap.IntMap;
   END;

PROCEDURE NewDropValue*(): DropValue;
   VAR dv: DropValue;
BEGIN
   NEW(dv); dv.val.index:=keepSel; RETURN dv
END NewDropValue;


Проблема в том, что тип DropValue не LIMITED, а значит, при создании объекта клиентам модуля можно обходиться без NewDropValue. Если эта процедура необязательна к использованию, можно ли сказать, что это уже формально не конструктор, а просто "утилитарная функция"?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 24 Апрель, 2013 17:58 

Зарегистрирован: Понедельник, 30 Июль, 2007 10:53
Сообщения: 1538
Откуда: Беларусь, Минск
Я бы сказал, что конструктор - это инструмент, используемый на определённом участке жизненного цикла объекта. Одни языки созданы таким образом, что для прохождения данного участка жизненного цикла использование данного инструмента необходимо, а другие языки - нет.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 24 Апрель, 2013 18:28 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2935
Откуда: г. Ярославль
Даже если язык не поддерживает напрямую понятие конструктора, то, по-моему, процедура, порождающая объект и инициализирующая его поля, определённо является конструктором. Вполне, так сказать, формальные признаки.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 24 Апрель, 2013 18:51 

Зарегистрирован: Понедельник, 30 Июль, 2007 10:53
Сообщения: 1538
Откуда: Беларусь, Минск
Да, я тоже так думаю.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 24 Апрель, 2013 20:18 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
По определению, конструктор это метод класса и вызывается ПРИ создании экземпляра, а не ДЛЯ его создания.
Поэтому получается, что в языках с конструкторами сначала new, а потом вызов конструктора.
Иначе пришлось бы new назвать конструктором. Ну, породил, значит "конструктор".
А в обероне вообще нет конструкторов, поэтому Мессенбёк имитирует работу среды по вызову конструктора, с помощью процедуры модуля.
Код:
TYPE
   T* = POINTER TO RECORD
      a- : REAL
   END;

PROCEDURE ( t : T ) InitT* ( x : REAL );
   BEGIN
      t.a :=x
END InitT;

PROCEDURE NewT* ( x : REAL ) : T;
   VAR t : T;
   BEGIN
      NEW(t); t.InitT(x);
      RETURN t
END NewT;

И здесь конструктором является метод InitT, который и нужен только потому, что поле класса только для чтения (что вполне обосновано). Рассуждения об удобстве такого решения можно оставить за скобками.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 24 Апрель, 2013 20:22 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
И для статических рекордов свойство "порождения" рекорда не имеет смысла, но метод .Init вполне может называться конструктором.

А вообще, чем точнее воспроизводить код, которым демонстрируют паттерн, тем больше уверенности, что ваш код можно будет обозвать по имени паттерна, а не "вольным пересказом перевода".


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 24 Апрель, 2013 20:28 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2935
Откуда: г. Ярославль
Пётр Кушнир писал(а):
По определению, конструктор это метод класса и вызывается ПРИ создании экземпляра, а не ДЛЯ его создания.
По чьему определению? Я привёл определение Мёссенбока, которое раскрывает суть, а не ограничивает форму. И не зависит от используемого языка.

Пётр Кушнир писал(а):
И для статических рекордов свойство "порождения" рекорда не имеет смысла, но метод .Init вполне может называться конструктором.
Это вряд ли возможно, использовать столь размытую терминологию.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 24 Апрель, 2013 22:29 
Аватара пользователя

Зарегистрирован: Суббота, 12 Июль, 2008 22:49
Сообщения: 575
Откуда: Россия, Санкт-Петербург
Если ПРИ создании - то конструктор,
А если ДЛЯ создания - то фабрика.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 24 Апрель, 2013 23:26 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2935
Откуда: г. Ярославль
Пётр Кушнир писал(а):
По определению, конструктор это метод класса и вызывается ПРИ создании экземпляра, а не ДЛЯ его создания. Поэтому получается, что в языках с конструкторами сначала new, а потом вызов конструктора.
Иначе пришлось бы new назвать конструктором. Ну, породил, значит "конструктор".
new - это аллокатор же, если скалькировать слово напрямую. А конструктор, по определению, приводит свежесозданный объект в допустимое состояние. В Object Pascal вызов аллокатора синтаксически совмещён с конструктором, в джаве и др. тоже (имя конструктора должно совпадать с именем класса), но всегда конструкторы связаны с двумя аспектами - создание объекта и приведение его в допустимое состояние. Конструктор как метод класса - так это же просто способ языковой реализации, как же ещё установить связь между конструктором и классом? Пришпандорили как метод, да и всё тут.

Посмотрел, как конструкторы реализованы в джаве, питоне, С++ и дельфи. Везде инициализация полей привязана к созданию объекта. То есть, языковый конструктор есть, по факту, реализация паттерна Конструктор. Надо разводить паттерн и языковую реализацию.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 25 Апрель, 2013 00:16 

Зарегистрирован: Понедельник, 30 Июль, 2007 10:53
Сообщения: 1538
Откуда: Беларусь, Минск
Не надо их разводить. Это логичное решение: не забываешь произвести инициализацию объекта. Между действиями выделения места в ОЗУ и инициализации с объектом ничего делать нельзя. Соответственно, обе эти вещи обязаны идти друг за другом. Объединение их в одно целое исключает вероятность ошибки в данном месте.

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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 25 Апрель, 2013 06:57 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2935
Откуда: г. Ярославль
Я имел в виду, что есть паттерн Конструктор как носитель смысла, и есть языковая реализация, которая есть форма. Содержание понятия Конструктора не определимо через его реализацию, поэтому я и считаю, что надо разводить паттерн и реализацию.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 25 Апрель, 2013 08:58 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Иван Кузьмицкий писал(а):
Я имел в виду, что есть паттерн Конструктор как носитель смысла
Я считаю, что нет паттерна Конструктор, а есть паттерн Фабрика. А Конструктор - это языковой механизм, который где-то присутствует, а где-то отсутствует.

В КП нам предлагают отсутствующие конструкторы компенсировать использованием фабрик.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 25 Апрель, 2013 09:50 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2935
Откуда: г. Ярославль
Не соглашусь. Паттерн Конструктор есть, и он описан у Мёссенбока, как и Фабрика у него же и у GoF. Фабрика и конструктор - разные паттерны, и это видно из описаний.

У Мёссенбока,
Цитата:
Назначением шаблона проектирования "фабрика" является создание объектов в условиях, где динамический тип объекта заранее неизвестен

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

Правда, у GoF понятие "конструктор" отождествляется с операцией (метод) в С++, которая есть автоматический инициализатор. Но это проблема гофов, я считаю :)

P.S. В языке Go убрана реализация паттерна конструктор. Как всегда, майнстрим подпитывается правильными оберон-идеями :)
https://sites.google.com/site/gopattern ... nstructors
Цитата:
Go doesn't support constructors, but constructor-like factory functions are easy to implement:


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 06 Май, 2013 14:08 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2935
Откуда: г. Ярославль
Чтобы закрыть тему, попытался разобраться в онтологии понятия "конструктор". Для этого пошарил в документации к PHP, Python, C++, C#, Java (тут и тут), Smalltalk, Free Pascal и даже PascalABC.NET. Не обошлось без Гради Буча.

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

Таким образом, мы имеем дело со схемой, не зависящей от языка программирования и состоящей из двух операций:
1) Порождение объекта (экземпляра класса)
2) Инициализация атрибутов объекта (приведение в допустимое состояние).

Поскольку эта схема повторяется очень часто и буквально везде, то она имеет право называться паттерном, шаблоном. И совершенно естественно назвать этот паттерн конструктором.

Дальше мы смотрим, как эта схема формализуется в разных ЯП. Естественно, по-разному. Либо это функция, возвращающая в качестве результата ссылку на созданный объект, либо метод инициализации, вызываемый автоматически, сразу после создания объекта обычным способом.

Отсюда вывод, даже два.

Первый: конструктор - это в первую очередь, паттерн проектирования, а не элемент описания ЯП. На языке Component Pascal конструктор реализуется (не "имитируется", а именно реализуется) очевидным и простым способом (указанным в одном из предыдущих сообщений).

И второй. Когда говорят, что в Обероне нет конструкторов, то всего лишь имеют в виду отсутствие поддержки паттерна в формальном описании языка, только и всего. Это совершенно не мешает использовать конструкторы в Оберонах.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 14 Апрель, 2016 15:07 

Зарегистрирован: Воскресенье, 03 Февраль, 2008 12:50
Сообщения: 249
Конструктор - это паттерн

Согласен с Иваном Кузьмицким: конструктор - это действительно паттерн. Паттерн создания экземпляра класса (объекта) (instantiation), который состоит из последовательного выполнения двух шагов:
  • Выделения памяти (allocation).
  • Инициализации (initialization).
В большинстве популярных языков этот паттерн действительно оформлен в отдельный языковой конструкт, но, замечу, что не во всех. Скажем, в Objective-C, создание объекта осуществляется явным последовательным вызовом двух методов с говорящими именами alloc и init:
Код:
Foo *f = [[Foo alloc] init];
При этом существует и метод new (конструктор как отдельный языковой конструкт), который объединяет действия alloc и init:
Код:
Foo *f = [Foo new];
однако, его использование считается менее предпочтительным, потому что он, во-первых, не поддерживает различные дополнительные инициализаторы (initWithString там всякие), а во-вторых, считается менее наглядным.

Конструктор требует дисциплины, если не облачён в отдельный конструкт

Так же отмечу, что приведённая выше в качестве примера идиома alloc-init из Objective-C, которая суть есть реализация паттерна "конструктор", требует определённой дисциплины от программиста. Например, язык в принципе позволяет только выделить память под объект, не инициализируя его,
Код:
Foo *f = [Foo alloc];
поэтому программист обязан до автоматизма заучить суть паттерна "конструктор": создание экземпляра класса = выделение памяти + инициализация (instantiation = allocation + initialization). Или ещё пример: метод init в подклассе сначала обязан вызывать метод init родительского класса:
Код:
- (id)init {
    self = [super init];
    ...
    return self;
}
И все эти правила по сути, конечно, не что иное, как составные части паттерна "конструктор".


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 14 Апрель, 2016 15:14 

Зарегистрирован: Воскресенье, 03 Февраль, 2008 12:50
Сообщения: 249
И ещё по поводу дисциплины. Можно, конечно, как предлагает Мёссенбёк в третьем издании Objektorientierte Programmierung in Oberon-2 (см. код Петра Кушнира), определять для типа T метод NewT в качестве одного единственного метода, ответственного за реализацию паттерна "конструктор". Но я бы тут дважды подумал, а стоит ли так делать?

Возможно, стоит ограничиться только инициализатором InitT и дисциплиной вызова InitT(t) после NEW(t) в клиентском коде, как всё тот же Мёссенбёк предлагал во втором издании всё того же опуса Object-Oriented Programming in Oberon-2 (см. раздел 8.1 Initialization of Objects). И не столько потому, что теряется наглядность, сколько потому, что всё равно остаётся возможность только выделить память посредством NEW без последующей инициализации. В КП для определённого типа записей (LIMITED), конечно, NEW запрещён за пределами определяющего модуля, но, во-первых, это касается только LIMITED-записей, а во-вторых, в Oberon-2 таких средств, вроде бы, вообще нет. Так что от дисциплины всё-равно никуда не деться: следует всегда создавать экземпляр класса T, используя обязательно определённый его создателем конструктор NewT, а не посредством NEW. С другой стороны, с конструктором NewT делаются возможными определённые вещи, невозможные с иcпользованием идиомы NEW-InitT, так что может Мёссенбёк и прав. :)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 14 Апрель, 2016 15:16 
Аватара пользователя

Зарегистрирован: Воскресенье, 12 Апрель, 2015 18:12
Сообщения: 1134
Откуда: СССР v2.0 rc 1
Цитата:
Если ПРИ создании - то конструктор,
А если ДЛЯ создания - то фабрика.

Мадзи, 100%. Плюсую.
Цитата:
new - это аллокатор же,

Иван! Порадовал)
Цитата:
Не надо их разводить. Это логичное решение: не забываешь произвести инициализацию объекта.

Незачёт, Валера. Тут Ваня Денисов задачу с массивом задачу решал. Зачем инициализировать его, если это сделает внешняя либа?
Цитата:
Я считаю, что нет паттерна Конструктор, а есть паттерн Фабрика.

Не согласен с тобой, Алексей, и далее поддерживаю позицию Ивана.
Цитата:
Таким образом, мы имеем дело со схемой, не зависящей от языка программирования и состоящей из двух операций:
1) Порождение объекта (экземпляра класса)
2) Инициализация атрибутов объекта (приведение в допустимое состояние).


Последний раз редактировалось prospero78 Четверг, 14 Апрель, 2016 15:21, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 14 Апрель, 2016 15:21 

Зарегистрирован: Воскресенье, 03 Февраль, 2008 12:50
Сообщения: 249
Madzi писал(а):
Если ПРИ создании - то конструктор,
А если ДЛЯ создания - то фабрика.

Нет, не так.
Если ПРИ создании - то инициализатор,
А если ДЛЯ создания - то конструктор или фабрика, в зависимости от того, какой шаблон создания объекта выбран.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 14 Апрель, 2016 15:24 
Аватара пользователя

Зарегистрирован: Воскресенье, 12 Апрель, 2015 18:12
Сообщения: 1134
Откуда: СССР v2.0 rc 1
Цитата:
Если ПРИ создании - то инициализатор,

Это и есть конструктор.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 14 Апрель, 2016 15:37 

Зарегистрирован: Воскресенье, 03 Февраль, 2008 12:50
Сообщения: 249
prospero78 писал(а):
Цитата:
Если ПРИ создании - то инициализатор,

Это и есть конструктор.

Нет. Ещё раз повторю, конструктор = аллокатор + инициализатор, где конструктор - прежде всего паттерн, а аллокатор и инициализатор - процедуры/методы. Конструктор можно реализовать как отдельный метод, но это не существенно.

На примере:
Код:
VAR
  f: Foo;
BEGIN
  NEW(f); InitFoo(f);
END;
Здесь процедура NEW - аллокатор, процедура InitFoo - инициализатор, а конструктор - всего навсего паттерн последовательного вызова этих двух процедур для создания экземпляра класса Foo. Можно оформит конструктор и в отдельную процедуру, но сути дела это не меняет.

Более-менее подробно будет так: если процедура/метод используется
  • для выделения памяти - то это аллокатор (NEW);
  • для инициализации объекта при его создании - то инициализатор (InitFoo),
  • для создания объекта (включающего и выделения памяти, и инициализацию) - то конструктор (ну или фабрика) (NewFoo, если таковой определён).


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 32 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
cron
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB