2009-06-18 3 views
2

Я отделяю свой код delphi от интерфейса и блоков реализации, т.е.Разделительный интерфейс и классы реализации в delphi?

EmployeeIntf.pas выглядит следующим образом

type 
// forward declaration 
    TScheduleList = class; 
    TDeparment = class; 
TEmployee = class(BDObject) 
    .... 
    function GetSchedules: TScheduleList; 
    function GetDepartment: TDepartment; 
end; 

TEmployeeList = class(DBList) 
    .... 
end; 

TEmployeeDM = class(BDDBobject) 
    ... 
end; 

Тогда у меня есть две единицы ScheduleIntf.pas & DepartmentIntf.pas, объявившие класс класса TScheduleList и TDepartment.

Тогда в моем основном блоке, который сочетает в себе все блоках выглядит так,

Unit BusinessDomain 
Interface 
uses 
classes 
    {$I Interface\EmployeeIntf.pas} 
    {$I Interface\DepartmentIntf.pas} 
    {$I Interface\ScheduleIntf.pas} 
Implementation 
uses 
SysUtils 
{$I Implementation\EmployeeImpl.pas} 
{$I Implementation\DepartmentImpl.pas} 
{$I Implementation\ScheduleImpl.pas} 
Initialization 
finalization 

end. 

Когда я скомпилировать этот компилятор выдает ошибку;

*Type TScheduleList is not yet completely defined* 

Как я должен это классы отдельно в каждом единичном файле (.pas), а затем сделать вперед заявление без компилятора бросания этой ошибки?

Класс themselvs огромен, и я бы предпочел их разделить таким образом.

Gath

ответ

14

Мой первый совет: Пропустить этот $ Включить вещь вообще. Как писал Uwe, найти более Delphi-подобное решение.

Если вы действительно хотите, чтобы остаться с стилем $ Include: ошибка, которую вы указываете, происходит, потому что декларации переходов не работают через блоки типа. Вы отправляете объявление TScheduleList в один блок, но определяете его в другом блоке. Чтобы вылечить это, пропустите ключевое слово «type» в * Intf.pas и вставьте его в BusinessDomain.pas перед включением.

+0

Он работал над вашим вторым советом, удалив ключевое слово type из * Intf.pas. Благодарю. – gath

+3

Я знаю, что у вас есть решение, которое «работает» для этого макета/стиля, но я был бы готов заложить деньги, чтобы вы вернули его обратно к истинному пути Delphi позже :) Вы теряете так много удобства в автоматизации и навигации кода , Тим – Despatcher

+0

Согласен. См. Ответ Тима. –

11

Боюсь, что нет никакой возможности разделить объявление класса на несколько файлов. Если классы такие большие, вы должны рассмотреть редизайн.

Другой альтернативой являются Интерфейсы:

type 
    IEmployee = interface 
    { public properties and methods of an employee } 
    ... 
    end; 

type 
    TEmployee = class(BDObject, IEmployee) 
    ... 
    end; 

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

+0

+1 Только то, что я собирался предложить. – skamradt

7

Ульрих вполне корректен (+1), в то время как вы можете манипулировать вашими включенными файлами для работы примерно таким образом, это не будет очень хорошим опытом Dev для вас.

Подумайте о директиве $ Include как о простом механизме замены текста, о том, что делает ваши юниты, а также ... единицами являются механизмы обзора (использует разделы, разделы типа и т. Д.), Они будут гораздо сложнее использовать в файл include, поэтому включить файлы обычно называются xxx.inc, а не xxxx.pas, поскольку они часто не будут выступать в качестве исходного файла сами по себе. Это, конечно же, делает их очень трудными в среде dev, поскольку тогда они фактически просто текстовые файлы не являются подходящими отлаживаемыми единицами.

+0

Разделение на самом деле делает все приложение удобным для навигации, бизнес-объекты не только логически разделены через классы, но и физически путем разделения единиц, легко найти их и naviagte. – gath

+4

Позволяет провести этот разговор за 6 месяцев :-) –

1

Возможно, мой предыдущий комментарий был немного самонадеянным ... Повторяя ваш вопрос, я думаю, вы, возможно, неправильно поняли, как использовать юниты и, в частности, директиву «uses».

Вы можете объявить отдельные классы как интерфейс и реализацию в одном единичный файле:

unit EmployeeDBCLassesU 

uses system, DB, Blah, blah; // Units needed by this unit 

interface 

type 

TEmployeeList = class(DBList) 
    Procedure DoSomething; 
end; 

TEmployeeDM = class(BDDBobject) 
    Procedure DoSomething; 
end; 

implementation 

{TEmployeeList} 

Procedure TEmployeeList.DoSomething; 
begin 
... 
end; 

{TEmployeeDM } 

Procedure TEmployeeDM.DoSomething; 
begin 
... 
end; 

Тогда позже использовать их elsewehere:

Unit BusinessDomain 

interface 

uses EmployeeDBCLassesU; // MY units needed by this unit 
. 
. 
. 

Это приносит все определение класса, чтобы BusinessDomain

и вы можете сделать

TBusinessDomain = class(BDDBobject) 
    EmployeeList: TEmployeeList; 
    EmployeeDM: TEmployeeDM; 
    . 
    . 
    .; 
end; 

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

1

Если вы действительно хотите разделить интерфейс и реализацию, посмотрите на Modula2. Это также приложение типа pascal, но оно использует два файла для каждой «единицы». Один для интерфейса и один для реализации.

Другим решением является разделение файлов или определений классов и запись пользовательского препроцессора, который связывает эти (текстовые) вместе. У вас тогда есть что-то вроде:

unit BusinessDomain 
interface 
uses 
classes; 

type 
    Employment = class from Interface\EmployeeIntf.pas; 
    Department = class from Interface\DepartmentIntf.pas; 
    Schedule = class from Interface\ScheduleIntf.pas; 

implementation 
uses 
    SysUtils; 

external define 
    Employment = class from Implementation\EmployeeImpl.pas; 
    Department = class from Implementation\DepartmentImpl.pas; 
    Schedule = class from Implementation\ScheduleImpl.pas; 
end; 

end. 

С Delphi 2009 вы можете выпускать команды до и после фазы сборки. Так технически это возможно.

+0

Каким будет преимущество пользовательского препроцессора над решением $ Include? –

+0

Я думаю, что это вопрос вкуса. Включить файлы не соответствуют духу delphi. С препроцессором вы можете более или менее расширить язык. –

+4

Согласовано. Включить файлы отлично подходят для настройки блоков IFDEF-DEFINE для целей конфигурации, но если у вас есть какой-либо фактический код, вы обычно делаете что-то неправильно. –

2

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

Сегодня наиболее распространенным использованием включенных файлов является включение блока кода, который должен быть разделен между несколькими файлами, а не может использоваться только с другого устройства. Как отметил Мейсон в другом комментарии, это будут блоки IFDEF-DEFINE для определения таких вещей, как то, какие параметры компилятора должны быть включены, и какие определения должны быть включены в проект в целом. Мы больше не связаны пределом 64k в исходном файле.

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

Мое предложение было бы использовать интерфейсы, как предлагал Уве. Они предназначены не только для COM и могут решить ваше желание отделить «интерфейс» от «реализации».

+0

Я использую комбинации клавиш WordStar до настоящего времени !! :-) –

+1

Возвращение в дельфи, как путь. – gath

+0

Хороший человек, правила Stackoverflow OK! – Despatcher

Смежные вопросы