Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2016.01.24;
Скачать: [xml.tar.bz2];

Вниз

Рассечение программы на модули.   Найти похожие ветки 

 
Pavia ©   (2015-05-20 20:08) [0]

Давно хотел спросить. Как делить программу на модули? Хотелось бы почитать рекомендации.

Библиотеки делятся на стационарные и динамические.
Динамическая библиотека представляет собой отдельный проект. Поэтому в программе они подключаются через заголовочные файлы.

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

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


 
Ega23 ©   (2015-05-20 20:10) [1]


> Проблема в том что в Delphi нет namespace


Чёй-та?


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


var
 myObj: UnitName.ClassName;


 
Pavia ©   (2015-05-20 20:26) [2]


> Ega23 ©   (20.05.15 20:10) [1]

Забыл уточнить что речь идет о Delphi 7 и менее.
Разумеется в XE что-то на изобретали. Но это так и не решает проблемы.


function Round(var Goal:TLIntBase2; const a:TRational):Boolean; overload;
var
 Moddular:TLIntBase2;
 rs:TRelationship;
begin
 Result:=true;
 MyLongInt2VL.Create(Goal);
 MyLongInt2VL.Create(Moddular);
 MyLongInt2VL._Div(Goal, a.P, a.Q);
 MyLongInt2VL._Mod(Moddular, a.P, a.Q);
 MyLong._shl(Moddular,Moddular,1);
 MyLongInt2VL.Compare(rs, Moddular, a.Q);

 if rs<>rsLess then MyLong.Add(Goal,Goal, MyLong.LIntBase2(1));
 Goal.Sign:=a.Sign;
 MyLongInt2VL.Destroy(Moddular);
end;

Я не могу написать  "With UnitName of", где UnitName это MyLongInt2VL.
А в Си++  так можно.

#include <iostream>

int main() {
  std::cout << "Hello ";
  using namespace std;
  cout << "World." << endl; // Тут count идёт без приставки std::
}


Да и нет возможности в Delphi слить(объединить) interface разных файлов.


 
Pavia ©   (2015-05-20 20:29) [3]

По прошу не уходить в сторону от первого вопроса.


 
Ega23 ©   (2015-05-20 20:32) [4]

function Round(var Goal:TLIntBase2; const a:TRational):Boolean; overload;
var
 Moddular:TLIntBase2;
 rs:TRelationship;
begin
 Result:=true;
 MyLongInt2VL.Create(Goal);
 MyLongInt2VL.Create(Moddular);
 MyLongInt2VL._Div(Goal, a.P, a.Q);
 MyLongInt2VL._Mod(Moddular, a.P, a.Q);
 MyLong._shl(Moddular,Moddular,1);
 MyLongInt2VL.Compare(rs, Moddular, a.Q);

 if rs<>rsLess then MyLong.Add(Goal,Goal, MyLong.LIntBase2(1));
 Goal.Sign:=a.Sign;
 MyLongInt2VL.Destroy(Moddular);
end;


Жесть какая.
Не хочу больше рассуждать.


 
Jeer ©   (2015-05-20 20:54) [5]

Если честно - какой-то бред от неверного понимания концепций структурного и функционального программирования, от слова - совсем.


 
Pavia ©   (2015-05-20 21:42) [6]

С математическими библиотеками всегда жесть.


> Если честно - какой-то бред от неверного понимания концепций
> структурного и функционального программирования, от слова
> - совсем.

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

Данный код не отображает всех замыслов. А только показывает одну частную проблему. Я просто выбрал данный как лакмусовую бумажку, которая способна наглядно показать весь масштаб проблемы.


 
Ega23 ©   (2015-05-20 21:49) [7]


> А только показывает одну частную проблему.


И ещё раз: это никакая не проблема ни разу.

unit Unit1;

implementation

 TUnit1NameSpace = class
   class function Foo(): Integer; overload;
   class function Foo(....): string; overload;
   class function Bar(): Integer; overload;
   class function Bar(....): string; overload;
 end;

unit Unit2;

uses Unit1;
.....

function Round(var Goal:TLIntBase2; const a:TRational):Boolean; overload;
begin
 Result:=true;
 with TUnit1NameSpace do
 begin
    Foo;
    Bar;
    ....
 end;
end;


Все функции-процедуры делаешь классовыми, собирая их по нужным тебе NameSpace


 
Игорь Шевченко ©   (2015-05-20 21:57) [8]


> Как делить программу на модули? Хотелось бы почитать рекомендации


http://royallib.com/book/reymond_erik/iskusstvo_programmirovaniya_dlya_Unix.html

Читать. Кроме рекомендаций по разделению программы на модули в этой книге еще масса полезных рекомендаций. Им тоже желательно следовать.


 
Rouse_ ©   (2015-05-20 22:20) [9]

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


 
DVM ©   (2015-05-20 22:29) [10]


> Pavia ©   (20.05.15 20:08) 


> Проблема в том что в Delphi нет namespace, который бы объединил
> разные файлы в одно цельное пространство. Делить на модули
> не очень получается. Хотелось бы делить по объектам - один
> объект один файл.  Но как правило так сделать не получается,
>  так как между объектами есть перекрёстные ссылки.

Используйте интерфейсы и проблема исчезнет.


> Ega23 ©   (20.05.15 20:10) [1]
>
> > Проблема в том что в Delphi нет namespace
>
>
> Чёй-та?
>

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


 
DVM ©   (2015-05-20 22:31) [11]


> Ega23 ©   (20.05.15 21:49) [7]


> Все функции-процедуры делаешь классовыми, собирая их по
> нужным тебе NameSpace

Ну это не то же самое. Функции не могут при таком подходе находиться в разных модулях, но в одном неймспейсе. Как и классы.


 
Ega23 ©   (2015-05-20 22:35) [12]


> Ну это не то же самое. Функции не могут при таком подходе
> находиться в разных модулях, но в одном неймспейсе. Как
> и классы.


Не очень понимаю, зачем это нужно в принципе.


 
Jeer ©   (2015-05-20 22:38) [13]

Выносите мат. и прочий "мелкий" функционал на уровень функционального программирования.
Пример модульности, понятной по названиям:

tsvBmpRgn.pas              338
tsvColors.pas              222
tsvConsole.pas             196
tsvConst.pas               480
tsvCPU.pas                  31
tsvCRC64.pas                87
tsvCrypto.pas              443
tsvCtrl2RTF.pas            390
tsvData.pas                 95
tsvDataFile.pas            613
tsvDBIClass.pas            602
tsvDBIConst.pas             16
tsvDBVar.pas                23
tsvDict.pas                226
tsvDirIter.pas              76
tsvDSN.pas                 129
tsvDTime.pas               384
tsvExcel.pas               450
tsvExcelUtils.pas          138
tsvFFT.pas                 370
tsvFile.pas               1143
tsvFileCompare.pas         141
tsvFileShell.pas           259
tsvFilter.pas              167
tsvFilterBQ.pas            243
tsvFIR.pas                 706
tsvFuzzyFind.pas           128
tsvHardware.pas             35
tsvHTMLParser.pas          225
tsvInet.pas                192
tsvIniFiles.pas             53
tsvIntegr.pas              157
tsvIntegral.pas            257
tsvInterpol.pas             44
tsvISAM.pas               1440
tsvISAMConst.pas            23
tsvKeyb.pas                 79
tsvLangs.pas               249
tsvLT2UTC.pas               20
tsvMail.pas                188
tsvMath.pas                915
tsvMathConst.pas            59
tsvMathTypes.pas            35
tsvMathUtils.pas           162
tsvMatrix.pas              877
tsvMatrix256.pas           500
tsvMemIniFile.pas           32
tsvMsg.pas                  91
tsvNet.pas                 654
tsvNumbers.pas             464
tsvOptima.pas               68
tsvParse.pas                48
tsvParseSQL.pas             94
tsvQuery.pas               754
tsvRandom.pas              129
tsvReadTiff.pas            702
tsvReadTiffTags.pas        464
tsvRecoder.pas             379
tsvRegress.pas             113
tsvRegression.pas          456
tsvSAU.pas                  23
tsvSignals.pas             342
tsvSignal_.pas             418
tsvSolver.pas               28
tsvSort.pas                314
tsvSort2.pas               326
tsvSortList.pas            236
tsvSound.pas               353
tsvSQL.pas                 861
tsvSQLConst.pas             33
tsvStats.pas               521
tsvStrCol.pas             2598
tsvStrCon.pas             2598
tsvStrings.pas            2474
tsvSystem.pas              701
tsvTiming.pas              433
tsvWave.pas                274
tsvWaveUtils.pas           176
tsvWord.pas                214
Twain.pas                 2973


 
DVM ©   (2015-05-20 22:40) [14]


> Ega23 ©   (20.05.15 22:35) [12]

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


 
Ega23 ©   (2015-05-20 22:54) [15]


> DVM ©   (20.05.15 22:40) [14]


А, вот ты о чём.
Чёрт его знает. С одной стороны - неудобно. С другой - Ты всегда точно знаешь, что что бы ты не использовал в юните, это либо объявлено в этом же юните, либо в одном из тех, что прописаны в uses.
Хрен его знает, лучше это, чем граф из сишных инклудов, где чёрт ногу сломит, или нет.
Ну вот так вот заведено.


 
Pavia ©   (2015-05-20 22:56) [16]

В данном случае. Всё просто. Но когда делаешь каркас(FrameWork) то приходится делать двунаправленные связи.
Как бы по проще объяснить ...
Есть 3 модуля.
UCompiler, UCompilerError, ULexAnaliser
В каждом есть одноименный объект.
TCompiler, TCompilerError, TLexAnaliser

TCompiler - является каркасом. Каркас нужен для перехвата и подмены разных объектов и их поведения.  Он связывает все остальные модули.
Все вызовы идут через него. Поэтому перехват можно сделать легко через Dependency Injection (внедрение зависимостей).  

Двунаправленная связь означает что:
- При создание TLexAnaliser в него передаются ссылка на объект типа TCompiler.
- А в самом TCompiler хранится объект типа TLexAnaliser.

Для подмены достаточно породить объект от TLexAnaliser в котором будет перекрыт нужный метод и подсунуть его в TCompiler.

Если бы классы были в одном файле то можно было бы использовать.
TCompiler=class; // Forward (опережающее декларирование)
Но если разделить на два файла,то не получается  Forward (опережающее декларирование). Компилятор ругается на отсутствие реализации.

Что-бы проделать такое разделение приходиться использовать TObject. А после приведения типов. Что мне не нравиться.


Поэтому  в TLexAnaliser есть код
function TParser.NeedSimvol(Simvol: TSimvol): Boolean;
begin
if SimvolsEQ(CurrentSimvol(),Simvol) then
  begin
  ReadSimvol;
  Result:=True;
  end else
  begin
    Result:=False;
    Compiler.Error.Add(100,Simvol.Value);
  end;
end;


function TGramAnaliser.ReadNextSimvol: TSimvol;
begin
 repeat
   Result:=(Compiler.LexAnaliser as TLexAnaliser).ReadSimvol;
 until Not(Result.Kind in [skSpace,skComment]);
end;


А в TCompiler такой

procedure TCompiler.Reset;
var
LexAnaliser:TFileLexAnaliser;
GramAnaliser:TGramAnaliser;

begin
LexAnaliser:=(FLexAnaliser as TFileLexAnaliser);
LexAnaliser.Reset;
GramAnaliser:=FGramAnaliser as TGramAnaliser;
GramAnaliser.Reset;
end;


 
DVM ©   (2015-05-20 23:03) [17]


> Pavia ©   (20.05.15 22:56) [16]


> Что-бы проделать такое разделение приходиться использовать
> TObject. А после приведения типов. Что мне не нравиться.
>  

Используйте интерфейсы. Интерфейсы вынесите в отдельные модули.


 
DVM ©   (2015-05-20 23:05) [18]


>  Pavia ©

Код должен зависеть от абстракций, а не конкретных классов.


 
Ega23 ©   (2015-05-20 23:09) [19]


> Он связывает все остальные модули.


Он связывает абстрактные TCustomCompilerError и TCustomLexAnaliser. А про конкретные их реализации он ни сном ни духом.
Ну либо как в [17]


 
Pavia ©   (2015-05-20 23:10) [20]


> Используйте интерфейсы и проблема исчезнет.

Честно хотелось бы посмотреть пример. Понятно что интерфейсы можно использовать. Вынести все интерфейсы в отдельный файл. Но по сути они будет целиком дублировать описания класса. Я правильно понял?


 
DVM ©   (2015-05-20 23:20) [21]


> Pavia ©   (20.05.15 23:10) [20]


> Честно хотелось бы посмотреть пример.

Ну вот пример того как разрешить циклические зависимости с помощью интерфейсов и разнести классы по разным файлам.

Делаем интерфейс, кладем его в отдельный модуль uIMyInterface.pas:

IMyInterface1 = interface
...
end;

Делаем второй интерфейс, кладем его в отдельный модуль uIMyInterface2.pas:

IMyInterface2 = interface
...
end;

Делаем 2 класса реализующие интерфейсы:

TMyClass1 = class(IMyInterface1... )
...
private
 FMyIntf2: IMyInterface2;
end;

TMyClass2 = class(IMyInterface2... )
...
private
 FMyIntf1: IMyInterface1;
end;

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


 
Ega23 ©   (2015-05-20 23:20) [22]


> Я правильно понял?


Может быть для начала Гради Буч?
http://www.helloworld.ru/texts/comp/other/oop/ch01.htm


 
Ega23 ©   (2015-05-20 23:21) [23]


>  но используют через интерфейсы друг друга.


И хрен их просто так теперь убьёшь. :)


 
Pavia ©   (2015-05-20 23:24) [24]


> DVM ©   (20.05.15 23:05) [18]
> >  Pavia ©Код должен зависеть от абстракций, а не конкретных
> классов.
>
>
> Ega23 ©   (20.05.15 23:09) [19]
> > Он связывает все остальные модули.Он связывает абстрактные
> TCustomCompilerError и TCustomLexAnaliser. А про конкретные
> их реализации он ни сном ни духом.Ну либо как в [17]


Это раздувания кода в 2 раза почём зря. В 4 если считать от функционального подхода. Пока будешь писать забудешь о чем думал. По этому от такого подходя решено было отказаться и сразу писать код реализации поумолчанию(defult) минуя абстракцию.
Тем более код не предполагает многочисленных изменения. Поэтому тесная связь между классами меня устраивает.

Совсем забыл написать, как я предполагаю модули они тесно связаны в отличие от библиотек которые самостоятельны. (Просто как-то терминологию ещё не придумал поэтому как бы так)


 
DVM ©   (2015-05-20 23:26) [25]


> Pavia ©   (20.05.15 23:24) [24]


> Это раздувания кода в 2 раза почём зря.

И увеличение гибкости кода даже не в 2, а в N раз пропорционально количеству введенных абстракций.


 
DVM ©   (2015-05-20 23:29) [26]


> Pavia ©   (20.05.15 23:24) [24]


> Поэтому тесная связь между классами меня устраивает.

Так устраивает ли нет? В одном модуле они будут тесно и хорошо связаны друг с другом. Они даже дружественными будут там и даже Private секции будут видеть друг у дружки.


 
Кто б сомневался ©   (2015-05-21 00:30) [27]


> Хотелось бы делить по объектам - один объект один файл.
>  Но как правило так сделать не получается, так как между
> объектами есть перекрёстные ссылки.


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


 
Германн ©   (2015-05-21 00:48) [28]

Удалено модератором


 
Кто б сомневался ©   (2015-05-21 00:57) [29]


> Кто б сомневался ©   (21.05.15 00:30) [27]


Просто когда проект вырастает, и в нем будет куча модулей - программисту будет сложно вспомнить что-где в каком модуле. А если делать один объект - один юнит - это будет сишный ад.


 
Кто б сомневался ©   (2015-05-21 01:10) [30]


>
> function TGramAnaliser.ReadNextSimvol: TSimvol;
> begin
>   repeat
>     Result:=(Compiler.LexAnaliser as TLexAnaliser).ReadSimvol;
>
>   until Not(Result.Kind in [skSpace,skComment]);
> end;


Еще можно сделать событие. TGramAnaliser.OnReadNextSimvol - и где то в центральном классе использовать оба класса, который перехватывает событие от TGramAnaliser.

Еще можно при создании TGramAnaliser в конструкторе кидать ссылку на нужный метод из Compiler. И TGramAnaliser будет его вызывать когда нужно.
Таким образом программист будет видеть что конкретно используется в этом классе из класса Compiler.

А вообще что-то не логично в этом коде:



 LexAnaliser:=(FLexAnaliser as TFileLexAnaliser);
 LexAnaliser.Reset;
 GramAnaliser:=FGramAnaliser as TGramAnaliser;
 GramAnaliser.Reset;



Эти классы должны быть наследованы - кто-то от кого-то. И вызов Reset у потомка, должен вызывать каскад ресетов у предков. Так проще для понимания кода человеком - меньше путанницы..
Послушай DVM он правильно говорит.


 
Кто б сомневался ©   (2015-05-21 01:12) [31]


> Эти классы должны быть наследованы - кто-то от кого-то


Потому что они делают судя по названию похожие задачи, значит возможно нужно сделать базовый абстрактный класс. Например как у TStream.


 
Кто б сомневался ©   (2015-05-21 01:26) [32]


> Pavia ©   (20.05.15 23:24) [24]
>
>
> > DVM ©   (20.05.15 23:05) [18]
> > >  Pavia ©Код должен зависеть от абстракций, а не конкретных
>
> > классов.
> >
>
> Это раздувания кода в 2 раза почём зря.


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

TClass1 = class

 function DoIt: boolean; virtual; abstract;
 procedure SomeProcess;
end

procedure TClass1.SomeProcess;
begin
 Result := Doit; // сработает у потомка, а мы здесь получим результат.
end;


 
Юрий Зотов ©   (2015-05-21 08:40) [33]

> - При создание TLexAnaliser в него передаются ссылка на
> объект типа TCompiler.
> - А в самом TCompiler хранится объект типа TLexAnaliser.


И возникает проблема кольцевой ссылки - так? Если да, то все просто - один uses (или оба) надо перенести в implementation. Такая ссылка кольцевой не считается.


 
Pavia ©   (2015-05-21 12:04) [34]


> И возникает проблема кольцевой ссылки - так? Если да, то
> все просто - один uses (или оба) надо перенести в implementation.
>  Такая ссылка кольцевой не считается.

Это так и сделано. Вопрос не в кольцевой ссылке, а в кольцевом интерфейсе. Его надо выносить на верхний уровень. Чего как-бы не хотелось делать так как получается, что у нас один интерфейс в 3-х местах дублируется. Но видимо это единственный вариант.


 
Ega23 ©   (2015-05-21 12:35) [35]


>  Но видимо это единственный вариант.


Единственный вариант - почитать Гради Буча. Там основы.


 
Pavia ©   (2015-05-23 15:10) [36]


> Единственный вариант - почитать Гради Буча. Там основы.

Прочитал Буча. Ничего нового. Хотелось бы более практические советы.


 
Pavia ©   (2015-05-23 15:51) [37]

Развиваю тему заодно хочу услышать критику:

> Библиотеки делятся на стационарные и динамические.
> Динамическая библиотека представляет собой отдельный проект.
>  Поэтому в программе они подключаются через заголовочные
> файлы.
>
> Так вот основной код программы и код стационарных библиотек
> делятся на модули.

Префиксы в именах модулей.
U - модуль;
L - статическая библиотека;
I - интерфейсный модуль;
H - заголовочный файл.

Папки.
В папке src - храним исходный код
В подпапках src хранятся библиотеки.
При задействовании библиотеке подключение подключается библиотека L или H.
К примеру:
uses LMyLib;

Файл статической библиотеки L представляет собой объединенную интерфейсную часть модулей U из которых состоит эта библиотека.

Это позволит избавиться и не писать кучу разных uses UUnit1,UUnit2, UUnit3, ..;

Объединение интерфейсной части предполагается при помощи автогенератора. На первых парах ручками.

unit LGeometry;

interface

uses UPoints, UPolygons;

{UPoints}

type
 PPoint2dR=UPoints.PPoint2dR;
 TPoint2dR=UPoints.TPoint2dR;

{UPolygons}

type
 FArea= function (Polygon:TPolygon):Real;
var
 Area:FArea=UPolygons.Area;
 
implementation

end.


В Delphi нет удобного механизма для ссылки на функций из другого модуля. Поэтому предполагается для отладки использовать виртуальные функции. А в реализе собирать в файл не только интерфейс (interface) но и реализацию (implementation).

Для решения перекрестных ссылок на разные интерфейсы из разных модулей предполагается создать интерфейсный файл I.
Почему нужен ещё один вид модулей? Дело в том что L нельзя использовать будет ошибка круговой ссылки модулей.

Проблемы такой иерархической структуры известны. Будет незначительная избыточность кода.  
К примеру в бибилотеке измерения времени мне нужно производить статическую обработку данных: усреднение, расчет доверительного интервала. Так как эта библиотека может использоваться в разных проектах то статическую обработку мне внести в библиотеку. Хотя у меня есть и библиотека для статической обработки с множеством функций. Но целиком её тащить не целесообразно. Поэтому там где будут использоваться обе этих библиотеке  будет дублироваться код этих двух функций(mean, Variance)


 
Юрий Зотов ©   (2015-05-23 18:02) [38]

> В Delphi нет удобного механизма для ссылки
> на функций из другого модуля.


А это что?

unit Unit1;

interface

 function Sum(x, y: extended): extended;

implementation

function Sum(x, y: extended): extended;
begin
 result := x + y
end;

end.

// ==========================

unit Unit2;

implementation

uses Unit1;

procedure PrintSum;
begin
  WriteLn(Sum(1, 2))
end;

end.


 
Юрий Зотов ©   (2015-05-23 18:07) [39]

То есть, надо добавить всего одну строку - объявление функции.  (в примере это строка 5). После этого ссылайтесь на эту нее из других модулей сколько захотите.


 
Юрий Зотов ©   (2015-05-23 18:19) [40]

> Pavia ©

А по поводу разбиения на модули - почитайте про восходящее проектирование, в сети материалы на эту тему наверняка есть. VCL с ее кучей модулей по этому принципу и построена - и все нормально, никаких проблем.

Суть в том, что на первом этаже лежат модули, ни от чего не зависящие (например, в VCL это модуль Windows). А на каждом следующем этаже лежат модули, зависящие только от модулей на предыдущих этажах (например, SysUtils, затем Classes и т.д.).


 
Pavia ©   (2015-05-23 20:48) [41]


> > В Delphi нет удобного механизма для ссылки> на функций
> из другого модуля.А это что?

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


 
Pavia ©   (2015-05-23 20:51) [42]


> Суть в том, что на первом этаже лежат модули, ни от чего
> не зависящие (например, в VCL это модуль Windows). А на
> каждом следующем этаже лежат модули, зависящие только от
> модулей на предыдущих этажах (например, SysUtils, затем
> Classes и т.д.).

Это не суть. Это называется поднять руки и сдаться.



Страницы: 1 2 вся ветка

Форум: "Прочее";
Текущий архив: 2016.01.24;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.61 MB
Время: 0.003 c
15-1410853148
Kerk
2014-09-16 11:39
2016.01.24
DelphiAST - каждому по автошеме


15-1432299372
Дмитрий С
2015-05-22 15:56
2016.01.24
посоветуйте чтиво по postgresql


15-1432556013
Jeer
2015-05-25 15:13
2016.01.24
Занятно:


15-1432503004
Юрий
2015-05-25 00:30
2016.01.24
С днем рождения ! 25 мая 2015 понедельник


15-1432380919
Pavelnk
2015-05-23 14:35
2016.01.24
RAD 2010 конфликтует с виндой





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский