Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Виннипух и вся честная компания или Слонопотама я и не вижу.  (Прочитано 23443 раз)
0 Пользователей и 10 Гостей смотрят эту тему.
Igel
Опытный

ru
Offline Offline
Пол: Мужской

« : 07-04-2006 16:02 » 

Классы, объекты, БД и все это вместе.
Сразу скажу, что я работал с классами и объектами. Создавал их и использовал в своих программах.
Но всегда меня волновал вопрос связи БД и объекта – раз. Связь объекта и интерфейса пользователя – два.

В общем задавался проблемой, но так до конца решение не довел. В жизни есть много способов решить задачу.
И как говориться решал задачи как умел.

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

Вот я и начал не спеша составлять технический проект, модель системы, список задач, объектная модель. В общем дошел до предела того что я знаю и могу, а главное понимаю.
Составил я значит модель основных объектов задачи. И не спеша начинаю продумывать методы свойства и параллено о реализации. тут-то до меня и доходит, что я как-то сильно все идеализировал, точнее не все понял. Встали у меня следующие вопросы:
1. Есть объекты классов. Данные храняться в БД, оптимально сточки зрения данных. Как, и на каком этапе данные изменяются, попадают в объект и вообще как реализовать работу?
Решение 1: С данными должен работать Самый главный Объект задачи. Все остальные объекты получают данные из БД в момент создания. С изменением не ясно.
Решение 2: Все объекты наследуют от базовых объектов возможность работы со своими данными.

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

Код:
Объектная модель технологии.
[b]Технология типовая[/b]
--Документы технологии (ТЛ, ВТД, КТТП, ЛРИ)
--Коллекция элементов технологии.
----Элемент технологии
------ВО
------Базовый документ (КТИ или ВТП)
------Коллекция КЭ
--------КЭ
------Коллекция СВО
--------СВО

[b]Технология групповая/единичная[/b]
--Документы технологии (ТЛ, ВТД, ВД (только для групповой), ЛРИ)
--Элемент технологии
----ВО
----Базовый документ КТП
----Коллекция КЭ
------КЭ
----Коллекция СВО
------СВО

З.Ы. В общем что не понятно задавайте вопросы. Искуством излагать свои мысли не славился.
Записан

Ёжики, это не только ценные шкурки...
Alf
Гость
« Ответ #1 : 07-04-2006 22:45 » 

1. Если объектная модель предметной области и модель данных разрабатывались совместно и хорошо соответствуют друг другу, рекомендую методику, которой сам обычно пользуюсь.

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

2. Тут ничего не понятно. Возможно, можно тоже изобрести интерфейс для этой цели. Но вообще нужно бы детализовать.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 08-04-2006 14:06 » 

Igel, мне кажется, твои вопросы о взаимодействии с БД, мысли по поводу главных и второстепенных объектов несколько туманны из-за восприятия БД в системе как внешнего элемента, насильственно вбиваемого между объектами. С интерфейсом пользователя относительно выполнения запросов в процессе тоже самое. Причём эти вопросы между собой взаимосвязаны.

По поводу БД. Если ты когда-нибудь использовал DFD для описания системы, то смысл БД в программе у тебя сомнений вызывать не должен. Хранилища - это: структурно срезы потоков данных системы, содержательно накопительные буферы и распределители информации. БД - вариант организации хранилищ.

Т.е. хранилище решает следующие задачи:
- сохраняет данные, если их обработка отложена;
- накапливает данные, если их последующая обработка блочная (или пакетная);
- аккумулирует данные из разных источников для одного приёмника;
- предоставляет данные из одного источника для разных приёмников.
Даже перечисленные задачи между собой по смыслу связаны и являются разными "гранями" единой функции хранилища, выражаемой различными словами.

Из функции хранилища выводятся необходимые его качества, например, соответствие структуры данных хранилища структуре потока данных, а также опционные: наличие системы идентификации единиц данных - различение данных, наличие метода поиска данных и др.

И вот если к БД относиться как к частному случаю хранилища, то вопросов о его месте в системе даже не возникает. Везде, где требуется выполнять функцию хранения данных, циркулирующих в потоках системы, причём оперативная память или обычные файлы не удовлетворяют каким-либо требованиям, начинают использовать БД.

Проще говоря, нужно изменить точку зрения и перестать относиться к БД как к чему-то отдельному от программы. БД не имеет самостоятельной ценности и смысла, а лишь в контексте какой-то проблемной области (более широко) или прикладной задачи (более узко), которые выражаются в программной системе.

Аналогично с интерфейсом пользователя. Если брать за основу программы категорию алгоритма - последовательности действий, - получаем систему, в которой алгоритм управляет данными. Отсюда и возникает образ потребности на некоторых шагах алгоритма запрашивать данные. Другое дело, когда в основе программы лежит система объектов, тогда данные управляют алгоритмом, тогда алгоритм создаётся в процессе изменения данных, действий пользователя и т.п. явлений. Тогда вопрос о том, как организовать ввод данных, даже не встаёт (в том смысле, в каком ты его задал).

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

Собственно, так и строятся информационные системы, моделирующие бизнес-процессы, и т.п.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Igel
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 08-04-2006 15:21 » 

1. Если объектная модель предметной области и модель данных разрабатывались совместно и хорошо соответствуют друг другу, рекомендую методику, которой сам обычно пользуюсь.
Не силен в терминах, но предметную область задачи я изучил. Модель не составил, но описал для себя. Модель данных не разрабатывал, думал в процессе разработки будут выявлены необходимые данные и структуры.

Цитата
Объекты, которые хранятся в базе данных, обычно имеют методы GetFromDataBase (фабричный метод) и PutIntoDataBase, которые, как нетрудно догадаться, извлекают объект из базы данных и сохраняют его состояние в оной. Чтобы не забыть оснастить объекты этими методами, можно создать с этой целью интерфейс, если язык разработки это позволяет.
Объекты, данные которых хранятся? Или сами объекты хранятся в БД?
Понятие "фабричный метод" - что означает?
Язык позволяет, делаю на Дельфе!

Цитата
2. Тут ничего не понятно. Возможно, можно тоже изобрести интерфейс для этой цели. Но вообще нужно бы детализовать.
Я сам сейчас плохо представляю. Попытаюсь сказать по другому.
ООП в основном позволяет упростить представление и сам процесс программирования. Дальше, я хочу реализовать объекты так, что в зависимости от того, кто их пользует или как их пользует  - данные визуализировались.
Т.е. не программировать в форме чтение данных из объектов, потом вставка данных в компоненты, потом события на изменения, выбор и пр... Т.е. если у меня действующая модель, в которой уже прописаны иерархии, связи , то зачам это снова прописывать уже на уровне пользовательского интерфейса? Не проще-ли как-то связать, может через объект посредник компонент формы с объектом, который и будет отвечать за визуализацию данных и работу с ними пользователя.

Уфф. Димка, сейчас думаю о твоей теме! Улыбаюсь
Записан

Ёжики, это не только ценные шкурки...
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 08-04-2006 16:16 » 

Цитата
Модель не составил, но описал для себя. Модель данных не разрабатывал, думал в процессе разработки будут выявлены необходимые данные и структуры.
Как это? Модели нет, но она есть "для себя"?

Цитата
Понятие "фабричный метод" - что означает?
Паттерн проектирования. Смотри книжку "банды четырёх".

Цитата
Т.е. если у меня действующая модель, в которой уже прописаны иерархии, связи , то зачам это снова прописывать уже на уровне пользовательского интерфейса? Не проще-ли как-то связать, может через объект посредник компонент формы с объектом, который и будет отвечать за визуализацию данных и работу с ними пользователя.
Схема MVC (Model/View/Controller) уж лет 20-25 как изобретена. В той же книжке упомянута. Если взять её принцип, то можно подключить к ней и загрузку данных из БД.

Что же касается языковых средств, то в Visual Studio 2005 (а может и в .NET 2.0), говорят, есть средства автоматической подгрузки данных из БД в объекты. Но сам пока не смотрел возможности - пока не намечается проектов под .NET 2.0. Летом буду разбираться.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Igel
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 08-04-2006 17:38 » 

Цитата
Igel, мне кажется, твои вопросы о взаимодействии с БД, мысли по поводу главных и

второстепенных объектов несколько туманны из-за восприятия БД в системе как внешнего

элемента, насильственно вбиваемого между объектами. С интерфейсом пользователя

относительно выполнения запросов в процессе тоже самое. Причём эти вопросы между

собой взаимосвязаны.
ВОзможно. По этому и задаю вопросы, чтобы увидеть маяк в тумане. Только на счет

главных и второстепенных не понил. Да БД у меня пока еще прочно ассоциируется с нечто

внешним относительно программы, с которым программа должна работать.

Цитата
Если ты когда-нибудь использовал DFD для описания системы
Никогда не использовал, не известна мине эта аббревиатура.


По поводу БД. Если ты когда-нибудь использовал DFD для описания системы, то смысл БД

в программе у тебя сомнений вызывать не должен.
Цитата
Хранилища - это: структурно срезы потоков данных системы, содержательно накопительные

буферы и распределители информации.
БД - вариант организации хранилищ.
Та-ак, т.е. если условно отделить БД от основного тела, то можно хранилищем назвать

объект связывающий эти 2 элемента (программа и БД). Чисто условно. Причем организация

хранилища, как объекта получается немаленькая задача.

Цитата
Из функции хранилища выводятся необходимые его качества, например, соответствие

структуры данных хранилища структуре потока данных, а также опционные: наличие

системы идентификации единиц данных - различение данных, наличие метода поиска данных

и др.
Брр... С одной стороны все понятно, с другой - нет образа... Может как-то предметно,

если можно - примеры.

Цитата
И вот если к БД относиться как к частному случаю хранилища.
Я понил, посмотреть на БД как на один из многих вариантов расположения данных

хранилища. Пытаюсь, честно. Каждый раз как заходит вопрос о проектировании или когда

я задумываюсь о реализации у меня в голове единый образ из компонентов и данных. Как

доходит до программинга - так тупик, на деле не получается (с текущим набором знаний)

реализовать образ из головы.

Вот теперь я решил вопрос задать есть у меня модель объектная (не данных).

Реализовать классы - нефиг делать. Но классы-то должны данные свои откуда-то брать?

Вот тут и вступает в противоречие объектная модель и работа с Бд. Улыбаюсь
Че-то глупо как-то получается. Знаю, что решение есть, как-то приходило в голову, да

и читал где-то, но хочется понать, дойти своим умом - а не выходит. Борются в колове

какие-то костные идеи, стандарты... С восторгом вспоминаю себя когда учился -

пределов не было - все решалось...

Люди, а есть психологи - вправляющие мозги заблудшим программерам? Улыбаюсь

Цитата
Разложи алгоритм на множество состояний системы.
В принципе понятно. Это как описать события которые могут быть с каждым объектом?
Записан

Ёжики, это не только ценные шкурки...
Igel
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 08-04-2006 17:56 » 

Цитата
Как это? Модели нет, но она есть "для себя"?

Есть понятие предметной области, как взаимодействует. А моделью я понимал нечто описанное на каком-нибудь специяльном языке описания моделей, либо как-то условно.
Цитата
Понятие "фабричный метод" - что означает?
Паттерн проектирования. Смотри книжку "банды четырёх".
Посмотрю, обизательно. Млин... продают только вижу... В электронном виде выдержки нет нужной? Хотя почитать нужно всю...
Цитата
Схема MVC (Model/View/Controller) уж лет 20-25 как изобретена. В той же книжке упомянута. Если взять её принцип, то можно подключить к ней и загрузку данных из БД.
Во-во... Поищу, может статьи какие есть. Хотя ... ты же ходячая статья Улыбаюсь Может разъяснишь эту схему?

Цитата
Что же касается языковых средств, то в Visual Studio 2005 (а может и в .NET 2.0), говорят, есть средства автоматической подгрузки данных из БД в объекты. Но сам пока не смотрел возможности - пока не намечается проектов под .NET 2.0. Летом буду разбираться.
Важнее принципы и понимание сути процессов, а остальное приложится, по себе знаю.
Записан

Ёжики, это не только ценные шкурки...
Alf
Гость
« Ответ #7 : 08-04-2006 17:59 » 

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

Не есть хорошо.Это фактически означает, что программирование ведется без предварительного проектирования, а это все равно, что плыть на корабле без лоции или строить без чертежа. Куда-то в итоге приплывешь, конечно, и что-то соорудишь, но скорее всего приплывешь не туда и построишь не то, что хотел, а то, что получилось.

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

Объекты, данные которых хранятся? Или сами объекты хранятся в БД?
Понятие "фабричный метод" - что означает?
Язык позволяет, делаю на Дельфе!

Давай поясню на небольшом примере.

Прежде всего, "фабричный метод" обозначает статический метод, способный порождать экземпляр своего класса. Своего рода некоторое подобие конструктора, но не конструктор. В нашем случае фабричный метод будет использован для создания объекта, стостояние которого хранится в базе данных в одной из записей.

Теперь сам пример. Чтобы не напрягать фантазию, воозьмем избитый пример - объект соответствует сотруднику. Допустим, поначалу мы храним его уникальный табельный номер (может быть использован в качестве ключа таблицы сотрудников) и Ф.И.О.

В базе данных сущности "Сотрудник" соответствует таблица с двума полями:

1. TabNo: int, primary key.
2. Name: string.

В программе этой сущности соответствует некий класс:

Код:
class Person
{
  // Конструктор
  public Person(int tabno, string name)
  {
    _tabno = tabno;
    _name - name;
  }

  // фабричный метод - находит в базе данных запись по ключу
  // и создает объект на основе ее содержимого
  public static Person GetFromDataBase(int tabno)
  {
    ...
    найти запись с данным tabno, получить значения ее полей;
    if нашли
      return new Person(tabno, name);
    else
      return null; или выдать исключение, что лучше по ситуации подходит.
  }

  // сохранение состояния объекта в базе данных
  void PutIntoDataBase()
  {
    сохранить значения свойств объекта в соответствующих
      полях таблицы БД;
  }

  ...  // прочие свойства и методы класса

  // переменные состояния объекта
  private int _tabNo;
  private string _name;
}

Что-то в таком духе. Конечно, для реальной задачи это слишком просто, но примерная идея такая.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 08-04-2006 18:22 » 

Так, понятно, что ничего не понятно.

DFD - Data Flow Diagrams - диаграммы потоков данных. Объяснять, что это, и с чем едят - это надолго. Помнится, были всякие книжки по поводу использования DFD, в том числе на русском языке - Г. Калянова. Когда-то на interface.ru находились.

В общем, пока не просят, углубляться в этот вопрос не буду. Надо подумать, как объяснить проще без DFD...

Цитата
Это как описать события которые могут быть с каждым объектом?
Скажем так, важнее описать события, сообщения о которых приходят в систему извне. Например, действия пользователя. Если у тебя есть алгоритм, по которому нужно провести пользователя, разбей его на куски, могущие выполняться без ввода данных. Далее полагай, что пользователь вводом данных запускает каждый следующий кусок алгоритма. Разорви управляющую связь между объектами, приводящую к выполнению последовательности действий, и замкни её на пользователя или что-то ещё, что обеспечивает ввод данных. Но такой подход возможен, если не используются такие абстракции процессов, в которых точки разрыва не просматриваются.

Буду думать над более простым объяснением и примерами.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Igel
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 08-04-2006 18:27 » 

Не есть хорошо.Это фактически означает, что программирование ведется без предварительного проектирования, а это все равно, что плыть на корабле без лоции или строить без чертежа. Куда-то в итоге приплывешь, конечно, и что-то соорудишь, но скорее всего приплывешь не туда и построишь не то, что хотел, а то, что получилось.
Не сыпь соль на рану. Я просто не понимаю самого проектирования, знаю, что нужно - но не получается раскрыть все это...
В принципе то, что я делаю можно назвать проектированием, пусть я не состовляю модель, но для себя я честно пытаюсь описать всё возможное. Для примера есть чертеж не в ГОСТе, а в каком-то своем стандарте, с ГОСТом рядом не лежащим.

Цитата
В результате проектирования у тебя должна получиться объектная модель, по возможности соответствующая предметной области.
Во-от, объектную моделюшку я и составил именно по предметной области. Т.е. по описанию предметной области, которое в свою очередь отражает модель предметной области. То что я привел в начале темы - это схема взаимосвязи объектов.

Объекты, данные которых хранятся? Или сами объекты хранятся в БД?
Понятие "фабричный метод" - что означает?
Язык позволяет, делаю на Дельфе!

Давай поясню на небольшом примере.
Цитата
Прежде всего, "фабричный метод" обозначает статический метод, способный порождать экземпляр своего класса.
Что-то знакомое. Своими словами - это метод класса, он может использоваться когда нет объекта класса, по аналогии с Конструктором. А-а, да, ты-же написал... Улыбаюсь
Т.е. мы этот метод используем вместо конструктора, а смысл, почему нельзя реализовать чтение в конструкторе?
Ну ладно это метод чтения из БД. А вот метод записи в БД. Если это метод класса, то как этот метод связан с объектом, точне применяется он как метод объекта?

Цитата
Что-то в таком духе. Конечно, для реальной задачи это слишком просто, но примерная идея такая.
Пример доступный, я понил. Улыбаюсь Спасибо!

Дальше что? Есть у меня объектная модель - как по ней лучше организовать БД?
Я так понимаю, что реализация структуры БД зависит напрямую от реализации работы с "хранилищем".
Если применять описаный Альфом метод, то структура БД имеет один вид, если метод работы будет другой - то другая структура. Так?
Записан

Ёжики, это не только ценные шкурки...
Igel
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 08-04-2006 18:40 » 

Так, понятно, что ничего не понятно.
Улыбаюсь Если честно, то с одной стороны мне жутко неловко. Сам себя понять не могу и вас мучаю. С другой - не разберусь - вообще человеком -разумным можно не считаться.

Цитата
DFD - Data Flow Diagrams - диаграммы потоков данных. Объяснять, что это, и с чем едят - это надолго.
Не надо. Понял, что это специальная область из области архитектуры...

Цитата
Скажем так, важнее описать события, сообщения о которых приходят в систему извне. Например, действия пользователя.
Если у тебя есть алгоритм, по которому нужно провести пользователя, разбей его на куски, могущие выполняться без ввода данных. Далее полагай, что пользователь вводом данных запускает каждый следующий кусок алгоритма. Разорви управляющую связь между объектами, приводящую к выполнению последовательности действий, и замкни её на пользователя или что-то ещё, что обеспечивает ввод данных. Но такой подход возможен, если не используются такие абстракции процессов, в которых точки разрыва не просматриваются.
Собираем все последовательно:
1. Составляем алгоритм работы пользователя исходя из видения системы.
2. Описываем все действия пользователя:
2.1. цель
2.2. условия (общие, входные данные, результат нужный)
2.3. действия (тут активные действия пользователя и то, что должна сделать программа)
2.4. возможные исключения
3. В действия пользователя нужно включить какие действи порождаются?

Цитата
Буду думать над более простым объяснением и примерами.
Не важно просто или сложно, важно - понятно. Любой пример - вопросы будут.
Записан

Ёжики, это не только ценные шкурки...
Alf
Гость
« Ответ #11 : 08-04-2006 18:46 » 

Т.е. мы этот метод используем вместо конструктора, а смысл, почему нельзя реализовать чтение в конструкторе?

Тогда единственным способом создания объекта было бы его чтение из базы данных. Но представь себе, что к тебе пришел новый сотрудник. В базе его еще нет, и поэтому ты не можешь создать для него новый объект, который потом запишешь в базу. Замкнутый круг.
 
Ну ладно это метод чтения из БД. А вот метод записи в БД. Если это метод класса, то как этот метод связан с объектом, точне применяется он как метод объекта??

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

Дальше что? Есть у меня объектная модель - как по ней лучше организовать БД?

Попробуй такой подход: каждой сущности в объектной модели соответствует таблица базы данных, а каждой переменной состояния класса - поле БД подходящего типа (или совокупность полей). Нет гарантии, что это годится для любой задачи, но в моей практике часто работает.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #12 : 08-04-2006 19:05 » 

Цитата
Если честно, то с одной стороны мне жутко неловко.
Это мне жутко неловко, что по-человечески объяснить не могу.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #13 : 08-04-2006 20:36 » 

Возьмём для примера какую-нибудь логическую игру. У игры есть правила, и согласно этим правилам игроки выполняют ходы.

Например, шашки:
пока не конец игры
нц
активный игрок делает ход
если нужно, сделать активным другого игрока - передать ему ход
кц

Положим, в этом алгоримте необходимо организовать ввод хода пользователя.

Положим, в этом алгоритме необходимо предусмотреть возможность приостановки игры - сохранения её, выхода из программы, затем продолжения игры после загрузки программы.

Ввод хода в приложении с GUI, положим, осуществляется перетаскиванием мышью шашки по полю. Это означает, что алгоритм в описанном виде нами не применим, ибо когда управление передаётся пользвателю, он имеет возможность не только перетащить шашку, но и, скажем, сохранить игру, вызвать справку, отменить предыдущий ход, выйти из программы и много других разных действий, которые позволяет сделать хорошо проработанное игровое приложение.

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

Мы не можем кодировать алгоритм непосредственно, поэтому мы создаём из объектов среду возможностей, в которой пользователь сам может выполнять шаги алгоритма.

С другой стороны, пользователь может злоупотреблять возможностями или просто ошибиться. Например, он может попытаться перетащить шашку в недопустимую правилами клетку поля.

Т.е. из всех потенциальных действий пользователя некоторые разрешены, а некоторые запрещены. Разрешения и запреты определяются программой, исходя из её текущего состояния.

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

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

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

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

Однако, чтобы пользователь мог следовать алгоритму игры, все параметры алгоритма (текущие значения переменных, шаг и т.п.) сохраняются системе, образуя её определённое состояние. Это подобно тому, как при отладке программы, при пошаговом её исполнении отладчик сохраняет все значения переменных, регистры процессора и т.п. Отладчик позволяет пользователю выполнить различные дополнительные действия между командами программы: просмотреть содержимое участков памяти, изменить значение переменных и т.п.

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

Так как система может состоять из подсистем, возможно наличие множества хранилищ - для каждой подсистемы своё хранилище. И так далее вплоть до элементарных объектов. Функционал работы с хранилищем инвариантен для объекта, подсистемы или целой системы. По некоторому событию происходит сохранение, по другому событию - восстановление. Конкретные реализации зависят от внутреннего устройства сохраняемых объектов или систем. Именно в силу инвариантности "основные объекты" или "второстепенные объекты" как таковые теряют смысл. Нет существенной разницы между данными в БД и данными внутри объектов.

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

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

Один из простых способов согласования структуры БД и структуры объектов системы во время исполнения между собой Alf описал. Каждый объект может быть представлен таблицей в БД, указатели на другие объекты заменяются внешними ключами на записи других таблиц.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 09-04-2006 09:43 » 

Прошу прощения, что встреваю. У меня вопрос по фабрике классов.
Цитата
Цитата
Т.е. мы этот метод используем вместо конструктора, а смысл, почему нельзя реализовать чтение в конструкторе?
Тогда единственным способом создания объекта было бы его чтение из базы данных. Но представь себе, что к тебе пришел новый сотрудник. В базе его еще нет, и поэтому ты не можешь создать для него новый объект, который потом запишешь в базу. Замкнутый круг.
Если сотрудника нет, то нам все равно придется выдавать новому сотруднику табельный номер, тогда, перед созданием объекта нового сотрудника, нам достаточно будет внести в БД его номер и ФИО и теперь мы спокойно можем пользоваться конструктором. Alf, в твоем примере, это будет реализовано в фабрике, правильно? А если эти действия произвести до создания объекта, то нам не нужна фабрика, нам и конструктора класса хватит. Вопрос: это издержки (особенности) ООП, в результате чего мы не можем (или можем, но не должны этого желать) создать отдельный метод вне класса, который мог  бы избавить нас от создания фабрики или от каких-то трудностей (специально не написал "от других трудностей").?


Вопрос №2:
Этот вопрос перекликается со вторым. Может ли наличие фабрики быть необходимым в целях защиты от создания непроизвольного (несанкционированного) объекта класса? Т.е. мы защищаем разработчика от того, чтобы он не воспользовался конструктором класса, а воспользовался фабрикой. И к этому еще пристает один вопрос: можно ли тогда конструктор класса отправить не в public, а в private и есть ли вообще в этом хоть какой-то смысл?
« Последнее редактирование: 09-04-2006 09:48 от nikedeforest » Записан

ещё один вопрос ...
Igel
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 09-04-2006 16:59 » 

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

Не вижу замкнутого круга. Чисто практически объект создается - создается запись в конструкторе проверяется наличие данных в БД.

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

Цитата
Попробуй такой подход: каждой сущности в объектной модели соответствует таблица базы данных, а каждой переменной состояния класса - поле БД подходящего типа (или совокупность полей). Нет гарантии, что это годится для любой задачи, но в моей практике часто работает.
Хмм... Например у меня будет один объект класа А, два объекта класа Б и Н-ое количество объектов класса В.
Начнем с В - ясно, что все объекты класса имеют одинаковый набор полей. Организовать таблицу - не проблема.
Дальше хуже. Например класс А - отдельную таблицу для одного объекта? Как-то руки не поднимаются.
А если усложнить задачу - есть множество уникальных классов - как быть?
Хотя тут че-то меня торкнуло, а че я мелочусь? Нужна таблица для одной записи - будет. Но может есть другие решения?


Димка, почитал я твое. Респект, зачет. Афтар пиши исчо! Улыбаюсь
По существу. В принципе все что ты изложил я понял. Да там все понятно. Другое дело, что это только набросок теории. И этот набросок у меня в голове в принципе есть, со своими деталями - но есть, ты же это сделал доступнее и доходчивее.
Но в чем беда, пока это далеко до реализации (не программного кода, а решения).
Например, мне нужно определиться с концепцией "хранилища".
Т.е. готового решения нет, но есть общие тенденции.
Как мне прийти к выбору варианта реализации хранилища? Что-то попахивает эгоизмом, поэтому скажем так - ЧТО мне нужно сделать, что-бы понять как реализовать или понять что мне нужно?

Другая тема хранилища - работа с ним на уровне объектов и работа на уровне взаимодействия с БД или файлами.
Если не сложно, поделитесь мыслями, постараюсь обдумать и не писать сразу ответ, а проработать.
Записан

Ёжики, это не только ценные шкурки...
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #16 : 09-04-2006 17:25 » 

Цитата
Но в чем беда, пока это далеко до реализации (не программного кода, а решения).
Не понял... Я думал, что вполне описал метод реализации алгоритмов, которые могут содержать произвольные точки разрыва.

Цитата
ЧТО мне нужно сделать, что-бы ... понять что мне нужно?
...
Цитата: Льюис Кэролл "Алиса в стране чудес"
- Скажите, пожалуйста, куда мне отсюда идти?
- Это во многом зависит от того, куда ты хочешь прийти,- ответил
Кот.
- Да мне почти все равно,- начала Алиса.
- Тогда все равно, куда идти,- сказал Кот.
- Лишь бы попасть куда-нибудь,- пояснила Алиса.
- Не беспокойся, куда-нибудь ты обязательно попадешь,- сказал Кот,-
конечно, если не остановишься на полпути.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Alf
Гость
« Ответ #17 : 09-04-2006 18:35 » 

Не вижу замкнутого круга. Чисто практически объект создается - создается запись в конструкторе проверяется наличие данных в БД.

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

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

Фабричный метод и метод класса одно и тоже или нет? Второй метод - он не метод класса - так и думал.

Нет, не одно и то же.

Метод класса (или статический метод, это синонимы) - метод, который не соотносится с каким-либо экземпляром класса, а принадлежит самому классу. Это позволяет вызывать его самостоятельно, если экземпляр класса отсутствует. Собственно, именно это и требуется в нашем случае - создать экземпляр класса возможно лишь методом класса, иначе возникает проблема курицы и яйца.

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

Хмм... Например у меня будет один объект класа А, два объекта класа Б и Н-ое количество объектов класса В.
Начнем с В - ясно, что все объекты класса имеют одинаковый набор полей. Организовать таблицу - не проблема.
Дальше хуже. Например класс А - отдельную таблицу для одного объекта? Как-то руки не поднимаются.
А если усложнить задачу - есть множество уникальных классов - как быть?
Хотя тут че-то меня торкнуло, а че я мелочусь? Нужна таблица для одной записи - будет. Но может есть другие решения?

Еси специфика задачи такова, что она изобилует уникальными объектами, то IMHO это серьезный повод для того, чтобы задуматься: а адекватна ли реляционная модель данных для моделирования такой предметной области?

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

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

ru
Offline Offline
Пол: Мужской

« Ответ #18 : 09-04-2006 19:21 » 

Цитата
Основные механизмы SQL-сервера предназначены для эффективного поиска записей, удовлетворяющих определенным условиям, агрегатных операций над ними, отслеживания реляционной целостности... Ничего этого в данном случае не нужно. Может быть, имеет смысл подумать о сохранении состояния таких объектов, скажем, в файле XML?
Igel, при этом хранилище всё равно будет, и будет выполняться его функция, просто оно будет реализовано в другой форме - в форме XML документа, а не реляционной БД. Все функции сохранения и восстановления объектов, подсистем и целой системы останутся, просто изменится их содержание.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Alf
Гость
« Ответ #19 : 09-04-2006 19:27 » new

Если сотрудника нет, то нам все равно придется выдавать новому сотруднику табельный номер, тогда, перед созданием объекта нового сотрудника, нам достаточно будет внести в БД его номер и ФИО и теперь мы спокойно можем пользоваться конструктором. Alf, в твоем примере, это будет реализовано в фабрике, правильно? А если эти действия произвести до создания объекта, то нам не нужна фабрика, нам и конструктора класса хватит. Вопрос: это издержки (особенности) ООП, в результате чего мы не можем (или можем, но не должны этого желать) создать отдельный метод вне класса, который мог  бы избавить нас от создания фабрики или от каких-то трудностей (специально не написал "от других трудностей").?

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

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

Это не слишком удачное решение. Хороший стиль ООП - инкапсуляция, позволяющая прятать несущественные подробности реализации от клиента. Фабричный метод позволяет спрятать сам факт наличия БД. Тебе нужна информация о сотруднике табельный номер такой-то? - получи и распишись, а откуда она взялась - не твоя забота.

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

Резюме: создание фабрики классов - не такая обуза, от которой нужно искать избавления. Это не обременительно и в то же время избавит от массы проблем как сейчас, так и впоследствии.



Вопрос №2:
Этот вопрос перекликается со вторым. Может ли наличие фабрики быть необходимым в целях защиты от создания непроизвольного (несанкционированного) объекта класса? Т.е. мы защищаем разработчика от того, чтобы он не воспользовался конструктором класса, а воспользовался фабрикой. И к этому еще пристает один вопрос: можно ли тогда конструктор класса отправить не в public, а в private и есть ли вообще в этом хоть какой-то смысл?

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

Пример: сейчас я пишу интерпретатор языка управления процессором телефонной станции MML. В этом языке имеется множество синтаксических конструкций, результат парсинга которых заносится в соответствующие объекты. По смыслу такие объекты могут быть созданы лишь в процессе разбора фрагмента файла с текстом на MML и никак иначе. Сделав конструктор класса закрытым и снабдив класс фабричным методом Parse, я легко решаю эту задачу.

Конструктор можно сделать не только закрытым, но и защищенным. Если при этом класс является базовым для нескольких других, можно сделать еще один интересный вариант фабричного метода - виртуальный конструктор. Разумеется, понятия "виртуальный конструктор" нет ни в C++, ни в C#, тем не менее системные архитекторы вовсю ипользуют их, получая красивые решения.
Записан
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #20 : 09-04-2006 21:25 » 

Цитата
Разумеется, понятия "виртуальный конструктор" нет ни в C++, ни в C#, тем не менее системные архитекторы вовсю ипользуют их, получая красивые решения.
Цитата
А можно про это поподробнее, желательно с примером?
Рискну предположить, что конструктору передается указатель на функцию.
Записан

ещё один вопрос ...
Alf
Гость
« Ответ #21 : 09-04-2006 22:14 » 

Привести пример из реального проекта, пожалуй, будет слишком громоздко. Расскажу схематически, только суть, без второстепенных деталей.

Возьмем мой пример с интерпретатором языка MML. Конкретнее - то его подмножество, которое описывает правила маршрутизации телефонных звонков между коммутаторами.

Когда абонент набирает телефонный номер, его звонок может быть направлен тремя основными способами:

1. На автоответчик (например, "неправильно набран номер").
2. На абонентскую линию, если адресат подключен к тому же коммутатору.
3. На транк-группу, если адресат подключен к другому коммутатору. В этом случае нужно по таблице маршрутов найти соответствующую транк-группу и направить вызов в нее.

Моя задача - построить список возможных направлений для данного абонента, чтобы проверить правильность маршрутизации. Поскольку мне нужно заносить в один список три разновидности направлений, очевидно, что мне следует создать абстрактный класс Направление и три производных от него класса: Направление_Автоответчик, Направление_АбонентскаяЛиния и Направление_ТранкГруппа.

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

Строим программу разбора:

Код:
public abstract class Направление
{
  // защищенный конструктор
  protected Направление(...)
  {
    ... // код конструктора
  }

  // фабричный метод
  public static Направление РазобратьНаправление(...)
  {
    ПолучитьБукву(буква);
    switch (буква)
    {
      case 'А':
        return Направление_Автоответчик.РазобратьНаправление_Автоответчик(...);

      case 'Л':
        return Направление_АбонентскаяЛиния.РазобратьНаправление_АбонентскаяЛиния(...);

      case 'Т':
        return Направление_ТранкГруппа.РазобратьНаправление_ТранкГруппа(...);

    default:
      throw new Exception("Недопустимый код направления");
    }
  }
} // Направление

public class Направление_Автоответчик: Направление
{
  // защищенный конструктор
  protected Направление_Автоответчик(...): base(...)
  {
    ... // код конструктора
  }

  // фабричный метод
  public static Направление_Автоответчик РазобратьНаправление_Автоответчик(...)
  {
    ... // здесь - код для разбора конструкции
        // РазобратьНаправление_Автоответчик
    // разобрали, теперь создаем экземпляр класса
    return new Направление_Автоответчик(...);
  }
} // Направление

...
Примерно по той же схеме пишем код для оставшихся
двух классов
...

Фабричный метод родительского класса Направление на жаргоне ООП часто называется "виртуальным конструктором", поскольку он создает в результате не экземпляр базового класса, что в принципе невозможно, т.к. базовый класс - абстрактный), а экземпляр одного из дочерних классов, в зависимости от контекста программы. Это довольно устоявшаяся идиома.

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

Никаких указателей на функции мне тут не потребовалось, разумеется. Вообще, использование всевозможных низкоуровневых конструкций вроде указателей без крайней на то нужды - хакерство в худшем смысле этого слова. Не зря Некоторые языки, например. Java и C#, отказались от самого понятия указателя и прекрасно себя чувствуют. Конечно, в C++ без них обойтись порой невозможно, но и тут лучше блюсти меру.
« Последнее редактирование: 06-12-2007 17:37 от Алексей1153++ » Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines