Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  06:23[Войти] | [Зарегистрироваться]
Ответ на вопрос № 62346

20-05-2008 23:25
Давно уже задаюсь этим вопросом ;) Прочитав сообщение Cepгея Poщина »вопрос КС №58932« (от 29-01-2008 10:42) решил спросить у Вас. Как же все таки грамотно организовать связь (обмен данными) между несколькими модулями? Хотелось бы узнать не только про обмен данных, но и целесообразность разбиения на юниты, способы задания парамметров функции (записи, массивы в случае большого количества) и прочее, как бы смешно это не звучало. Просто мало опыта написания объемных программ и вот наконец дошел =) Поделитесь секретами или ссылкой на статьи!

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


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

15-09-2008 08:07 | Комментарий к предыдущим ответам
Кстати, matvey таки написал статью
Да, читал конечно, спасибо ему, интересные идеи.

15-09-2008 04:03
matvey:
Если данная схема реализации взаимодействия представляет интерес для народа, то в принципе для полного раскрытия вопроса необходимо писать статью с примерами кода.

ploop:
Почитал бы с удовольствием


Кстати, matvey таки написал статью:
http://delphikingdom.com/asp/viewitem.asp?catalogid=1374

14-09-2008 01:29 | Комментарий к предыдущим ответам
На самом деле, материалов в сети довольно много, натыкался на них, когда искал совершенно другие вещи, потому ссылки не сохранил. Смысл в том, что "внутренняя кухня" программы - то же, что интерфейс, только если интерфейс виден всем, то "внутренняя кухня" видна только программисту. Плохая организация программы отбивает напрочь желание работать с проектом дальше, развивать, совершенствовать, искать и исправлять ошибки. Но хорошая организация заставляет тянуться к проекту, в том числе и не только самого программиста, но и сторонних программистов (пользователи скорее всего в такую волочею вовлечены не будут, так как даже не подозревают, насколько важны пожелания по организацию интерфейса настоящему программисту, особенно если в команде нет дизайнера и тем паче если программист работает в одиночку). Пример тому - Linux с открытым исходным кодом - благодаря простоте своей внутренней организации над этим проектом работают миллионы программистов по всему миру. Потому Microsoft никогда не откроет исходные коды своих операционных систем, даже устаревших, вроде Windows 3.11, Windows 98/98/ME - просто забоится нападок со стороны мировой общественности о многочисленных недочетах. Даже в исходных кодах VCL, специально созданных для обозрения широкой публикой программистов и то обнаруживаются досадные "ляпы". В общем, я надеюсь, что вы прониклись идеей того, что внутренняя кухня - тот же интерфейс: разным людям нужен разный интерфейс, но все-таки определенные правила для большинства существуют. Предлагаю сформулировать ряд из них:
  • C тем, что количество глобальных переменных должно быть сведено к минимуму, знакомы многие. Но многие не понимают, почему это так. На самом деле, подобное ограничение связано с тем, что глобальные переменные могут меняться непредсказуемо - вызываемыми процедурами, например, или даже другими потоками. Именно поэтому цикл For не допускает для использования в качестве счетчика итераций глобальные переменные - потому что это грозит случайным изменением порядка выполнения работы и нарушением работы цикла. К примеру, возьмем знаменитый DecimalSeparator. Бог с ним, при использовании стандартных функций VCL ничего страшного не наблюдается. Но возьмем, например, некую процедуру MySuperProc из библиотеки стороннего разработчика. Пусть даже у нас будут исходные коды этой библиотеки - но при использовании процедуры мы считаем ее черным ящиком. Пусть до и после вызова мы выполняем действия, связаные с преобразованием чисел в строки и обратно. Мы НЕ МОЖЕМ гарантровать, что наш "черный ящик" оставил DecimalSeparator в том состоянии, в котором он был до вызова, хотя подсознательно пишем код, как если бы это было так. Неимоверная сложность отслеживания взаимодействий ДОЛЖНА ограничивать число глобальных переменных жизненно необходимым минимумом. Это не относится к глобальным функциям, вроде Printer, который часто путают с глобальной переменной. Эта не переменная - она не меняется, а возвращает значение "внутренней" переменной. Именно по этой причине рекомендуется использование свойств (property) в объектах (классах), а не полей. При изменении свойства мы можем оповестить все заинтересованные структуры через сеттер и сознательно РАСЧИТЫВАЕМ на возможность изменения. Если возможность изменения полей внутри выполнения процедуры недопустима, то необходимо создать их локальные копии, или деактивировать сеттер. Я для локальных копий использую префикс l, также как для private полей - префикс f, а для передаваемых в процедуры типа конструктора инициализирующих параметров - префикс a. Посмотрите функции, которые используют TFormatSettings. Пример приведен в »вопрос КС №33804«
    Вред глобальных настроек могу продемонстрировать еще одним примером. Вот сейчас ушел на полчаса от компьютера, а когда вернулся - экран горит. Лезу в настройки электропитания, а там - правильно, стоит тема "Intervideo...". И это с учетом того, что проигрыватель я удалил несколько месяцев назад, а тему электропитания приходится менять каждую неделю. На вирус подозрений нет - Касперский от июня с.г. молчит как рыба, но неприятный осадок регулярно все-равно остается. Вот бы настроить все личные настройки и сказать: "А теперь пока я ЛИЧНО не разрешу - никому не трогать настройки". Но такого, увы, нету.
  • >>> Не бросаться с места в карьер
    Точно. Не поддаваться настронию, что "я это за пять минут сделаю". Потом будете год расхлебывать то, что второпях наразрабатывали. Помните - каждый час, вложенный в проектирование, обернется несколькими днями экономии на этапе разработки. Экономить на разработке - себе во вред.
  • >>> Допустим нужно из главной формы вызвать модальную
    Для этого все просто - создаем функцию, которая бы редактировала значение переданного параметра. Например, типа string. Возвращаемый результат - типа boolean, как раз - произошло ли изменение. Ваш пример будет работать гораздо разумнее при оформлении:

    function GetSomeData(var S:string):boolean;
    begin
      Result:=false; // in case of failure
      with TSomeEditForm.Create(nil) do try
        Edit1.Text:=S; // вносим данные в поля формы
        Result:=ShowModal=mrOk; // редактируем.
          // При нажатии на Ok ДОЛЖНА проходить полная верификация данных.
          // Только если она прошла, ModalResult может принять значение mrOk.
          // Отмена должна проходить без дополнительных проверок.
        if Result then begin
          S:=Edit1.Text; // возвращаем в параметре значение
        end
      finally
        Free;
      end;
    end;


    Вызов будет очень простым и понятным:

    procedure Button1Click(Sender:TObject);
    var S:string;
    begin
      S:=Table1.FieldByName('Family').AsString;
      if GetSomeData(S) then begin
        Table1.Edit;
        Table1.FieldByName('Family').AsString:=S;
        Table1.Post;
      end;
    end;


    Вас больше не будут волновать проблемы, связанные с тем, что модули ссылаются друг на друга перекрестно - этого не будет никогда, модуль, в котором размещена GetSomeData никогда не узнает про модуль, в котором размещен Button1Click. Это ему просто не нужно. Мало того, такая процедура может импортироваться из DLL без каких бы то ни было ограничений, помимо передачи строк типа String, но их легко обойти, передавая PChar, или прочитав комментарий, вставляемый средой при генерации проекта DLL.
  • Вопрос, связанный с тем, что лучше передавать - список параметров, или одну запись или массив - сугубо риторический. В ряде случаев выбора вообще не остается. Когда Вы создаете поток средствами WinAPI (BeginThread на самом деле), то Вы обязаны либо уместить все параметры в один 32 разрядный параметр, либо передавать структуру. Во всех остальных случаях выбор между записью (массивом) и списком параметров диктуется личными предпочтениями программиста. Мне нравятся записи. Их легко копировать одной командой (например, с целью резервного хранения), их можно передавать в несколько разных процедур не раздувая кода. Например, пусть у нас есть программа для сложения двух чисел (трвиально, не правда ли?). Пусть мы хотим разнести ее на три модуля - ввод данных, расчет и печать отчета. Тогда при списке параметров мы будем иметь нечто такое:

    if InputData(Data) then try
      CountData(Data);
      PrintReport(Data);
    except
      PrintException(Data);
    end;


    При использовании списка параметров код будет чуть длиннее:

    if InputData(A,B) then try
      CountData(A,B,C);
      PrintReport(C);
    except
      PrintException(A,B);
    end;


    Здесь мы видим плюсы и минусы каждого метода. Плюс первого метода - во все процедуры передается одно и то же, с ним процедуры и работают. Это сродни объектно-ориентированному программированию, когда данные и обрабатывающий их код инкапсулирован в единое целое. На двух параметрах и одном результате это практически незаметно, но когда параметров станет много, плюсы этого метода становятся очевидными. Минус - передача лишних данных, например, в InputData неявно передается переменная С, которая будет хранить результат, хотя для ввода данных она явно излишня. А в PrintReport передаются входные параметры, которые там явно ни к чему (хотя с этим можно поспорить). Еще один минус - с точки зрения "черного ящика", у неправильно написанной процедуры в случае передачи списка параметров меньше шансов угробить входные данные - они будут передаваться как константы, тогда как при передаче записи подпрограмма может испортить все данные, или скомпрометировать их, если они являются секретными. Лучшим решением является комбинация этих двух способов. Настройки, с которыми работает подпрограмма, должны находиться в одном параметре (типа TFormatSettings), входные данные - в другом (передается как константа), а выходные - в третьем (передается как out параметр). Это обеспечивает достаточно хорошую защищенность от сбоев, хотя от компрометации данных и не защитит.
  • >>> Стоит ли передавать параметром компонент
    Нет, это излишне жесткое ограничение. Желательно, чтобы процедуры обработки не знали, откуда данные, даже если понятно, что "из лесу, вестимо". Желательно обрабатывать не файлы, а потоки TStream, это обеспечит максимальную универсальность. А процедуру для обрабоки файла я обычно делаю с тем же именем, перекрытую (overload), чтобы упростить себе жизнь.

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

27-05-2008 04:21 | Сообщение от автора вопроса
2 Бел Амор
Спасибо что поняли и направили в нужное русло ;) Ну что ж буду следовать завету Ленина :D

27-05-2008 03:50
>>> Ну и прочее в этом духе... Эт так первое что в голову пришло :)

Понятно, что это выдано "от балды"... Но, тем не менее, направление задано... :)
Ответил здесь: »сообщение 426 в теме №356 на БП«

26-05-2008 13:34 | Сообщение от автора вопроса
Согласен! Это так, пробный бросок =) Ну в частности:
  • Стоит заменять параметры глобальными переменными
  • Если парамметров слишком много - обединять их в массивы, создавать отдельный тип
  • Стоит ли передавать параметром компонент если он использеутся в теле процедуры не "поназначению"

Ну и прочее в этом духе... Эт так первое что в голову пришло :)

26-05-2008 13:17
>>> А можете что нибудь посоветовать касательно параметров процедур?

Вопрос не очень конкретен... Чуть поконкретнее?

26-05-2008 12:55 | Сообщение от автора вопроса
Ага, уже обращал на это внимание ;) А можете что нибудь посоветовать касательно параметров процедур?

26-05-2008 12:40
До кучи - способы обработки закрытия окна:

Общая информация: »вопрос КС №61703«
Примеры: »вопрос КС №49724«

26-05-2008 08:53 | Сообщение от автора вопроса
2 Бел Амор
Спасибо, что обратили внимание на мой вопрос :) Очень понравился Ваш пример из »вопрос КС №50045«. Вы определенно поняли какой ответ я хочу получить на свой вопрос ;)

26-05-2008 04:48
Ещё совет...
Достаточно часто приходится вводить что-либо в поля путём выбора из какого-либо списка. Часто для этой цели используют элементы с выпадающим списком вроде ComboBox'а. Я предпочитаю в таких случаях показывать полноценное окно со списком и кнопочками подтверждения и отмены. При этом возникает вопрос о возврате в вызывающую процедуру выбранного значения. Очень удобным является следующий способ:
1. В функцию выбора передаётся ссылка на целевой элемент. Обычно это поле редактируемого датасета. Передавать ссылку именно на поле очень удобно в том смысле, что, во-первых, в нём уже содержится исходное значение и можно спозиционировать курсор на элемент в списке, соответствующий текущему значению. Во-вторых, в него-же можно записать новое значение при подтверждении выбора прямо в функции выбора, ничего дополнительно не предпринимая на вызывающей стороне. И в-третьих, на вызываемой стороне ничего не надо знать о том, какому датасету принадлежит это поле, его имя и т.д., таким образом уменьшается количество передаваемых параметров и увеличивается универсальность.
2. Для тех редких случаев, когда на вызывающей стороне нужно знать произведён выбор или нет, функция возвращает значение типа Boolean.

Например:

procedure TForm1.Button1Click(Sender: TObject);
begin
  ChooseCustomer(tblOrder.FieldByName('CustomerId'));
end;

Полностью рабочий пример, иллюстрирующий такой подход (даже с dfm) можно посмотреть здесь: »вопрос КС №50045«
Хотя в нём присутствуют некоторые корявости, но идею он вполне иллюстрирует, кроме того, там можно почерпнуть и некоторые дополнительные идеи, не относящиеся напрямую к данному вопросу...

22-05-2008 13:56
Эксперимент провёл с одним связующим модулем, если грамотно продумать вполне можно использовать такой способ.
Допустим нужно из главной формы вызвать модальную, и получить результат в виде текста из поля Edit модальной формы, но не добавляя в Uses обоих модулей ссылки друг на друга. Вот что получилось:


// Добавляем новый модуль, пусть будет Unit3, и прописываем
// его в Uses Unit1 и Unit2
unit Unit3;

interface

type
  TPr = procedure(var S: string);

var
  _ShowForm,
  _GetText: TPr;

implementation

end.

// Unit2 - модальная форма
procedure GetText(var Text: string);
procedure ShowForm(var Text: string);

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
begin
  _GetText:=GetText;
  _ShowForm:=ShowForm;
end;

procedure GetText(var Text: string);
begin
  Text:=Form2.Edit1.Text;
end;

procedure ShowForm(var Text: string);
begin
  Form2.ShowModal;
end;

// Unit1 - главная форма
procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
begin
  _GetText(S);      // Просто вызываем процедуру из Unit3
  ShowMessage(S); 
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  S: string;
begin
  _ShowForm(S);
end;


22-05-2008 03:25 | Сообщение от автора вопроса
Поддержу ploop. Интересны любые способы, даже те которые имеют минусы, ведь ничто не совершенно ;)

22-05-2008 02:23
для полного раскрытия вопроса необходимо писать статью с примерами кода

Почитал бы с удовольствием

21-05-2008 23:07
Как же все таки грамотно организовать связь (обмен данными) между несколькими модулями?
Как я понимаю...
Что есть объект? Объект есть некая сущность, представляющая данные и методы для их обработки. Обычно для реализации объекта используется отдельный модуль. Соответственно, если несколько модулей (объектов) используют одни и те же данные, то значит они используют один и тот же объект, или (в других терминах) модуль с данными (модуль данных). Исходя из этого, ИМХО, обмен данными между объектами можно и нужно реализовывать через отдельный модуль данных, а события об изменении данных передавать через отдельный объект линка (типа линка на datasource, а не через события обекта, чтобы можно было отослать событие нескольким заинтересованным модулям) на экземпляр модуля данных. Тогда внутри каждого объекта можно сделать свой линк на общий обект и ловить специфичные события. При таком раскладе как раз получается, что общая информация может быть типизирована и при её изменении реагировать на это изменение будут только те объекты которые должны обработать данное изменение.
Например, имеется глобальный параметр настройки приложения - размер шрифта в многострочном редакторе. Когда пользователь выбирает новый размер шрифта диалог просто устанавливает данный параметр в общем модуле данных, далее модуль данных пытается через даталинк оповестить все окна, но только окна, которые имеют многострочный редактор изменят размер шрифта. Таким образом, окно настройки не знает об окнах в которых есть многострочный редактор (те огромный плюс - объекты, взаимодействующие через модуль данных не знают друг о друге и деталях реализации объхектов, что позволяет легко их модифицировать (или добавлять/удалять) не боясь наступить на грабли, связанные с тем, что объекты "завязаны" друг на друга), но изменив параметр в общем модуле данных оно изменяет соответствующий вид всех окон внутри приложения.
Недостатки такого подхода есть. То, что я вижу:
1) Параметры прописываются в коде и набор параметров и соответственно методов обработки изменяется от приложения к приложению, те нельзя написать некий универсальный компонент.
2) Возникает необходимость регистрировать объект в каждом модуле для получения событий изменений данных, что приводит практически к обязательной перегрузке конструктора/деструктора объекта и дополнительному коду.

Однако, на данный момент времени плюсы такого решения лично для меня перевешивают минусы.

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

21-05-2008 22:57 | Сообщение от автора вопроса
Спасибо, panda! 700 с лишним страниц из разряда "must have" - это надолго =) Ууу... да еще и с примерами, правда на С++ и Java :D

21-05-2008 05:39
Почитайте Паттерны проектирования и Рефакторинг - многие вопросы решатся.

21-05-2008 04:21 | Сообщение от автора вопроса
2 Cepгей Poщин
Все ниже написанное Вами истино, просто задавал вопрос для своего рода хинтов от гуру;)
Большая однако »тема на БП №383« обезательно пробегусь и полностью согласен с Вашим мнением:
>>>Может напишите статью на эту тему с примером реализации? Было бы интересно.
Возможно мне стоит конкретизировать то что меня интересует на данный момент, потому как вопрос слишком абстрактен для ответа, а сама тема заслуживает более детального расмотрения. Ну на счет деталей, это мое личное мнение. Люблю когда "все разложенно по полочкам"... хотя понимаю, что конечному пользователю не важно как и что у тебя написанно - главное чтобы работало =)
2 All
Друзья мои, мы же в Королевстве Delphi! Именно поэтому нужно соблюдать правило хорошего тона не только в общении, но и при создании своих шедевров;) А этикету учат еще в школе, так почему бы Вам не научить окружающих?

21-05-2008 03:34
Вы мне его рекомендовали как пример алгоритма обмена данными между модулями? Да.
Что еще можно порекомендовать.
Почитать http://www.delphikingdom.com/asp/talktopic.asp?ID=383
Смотреть исходники поставляемые с Delphi.
Умные книги прочесть.
Найти общие места и вынести их в отдельные модули.
Не бросаться с места в карьер, а предварительно думать о проекте в целом. Как он будет выглядеть через год-два? Как разбить его на такие модули, что бы при изменении функционала не пришлось править все модули?
Вопрос довольно концептуальный, типа "Четверостишья я уже научился писать, а как правильно написать поэму в стихах?!"

21-05-2008 02:28
Да, интересное чтиво, уже был ознакомлен =) Вы мне его рекомендовали как пример алгоритма обмена данными между модулями?

21-05-2008 02:06
Вот по-моему в тему: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=753

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
"Мы с тобой одной крови — ты и я!". Чьи это заветные слова?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования