« Поставить закладку » « Сделать стартовой »

« Форумы » « Блоги » « Статьи » « Новости » « Файлы » « Realcoding IRC » « Site map » « Поиск »


Главная Главная
Анонсы Анонсы
Форумы Форумы
Каталог Каталог
Поиск Поиск
Опросы Опросы
Книжный магазин Книжный магазин
Реклама на сайте
Публикации Публикации
Партнеры Партнеры
Карта Карта сайта
Рассылки Рассылки
RSS экспорт
Настройки Настройки
О нас пишут О нас пишут
Контакты Контакты
Гостевая книга Гостевая книга



ПнВтСрЧтПтСбВс
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
    Популярное
Создание установочного диска

Ускорение PHP-программ

ШИФРОВАНИЕ В DELPHI

Первый взгляд на HTML 5

Новые формы HTML5

Установка

Динамические SQL-запросы Oracle для ускорения выборок данных

Организация CSS-файлов: Совет 1 - Флаги

Сетевые сервисы

Создание апплетов для Windows с помощью Delphi




    Архив файлов



    Сообщества

    Документация

    Кто на сайте
Вы не зарегистрированы.
Имя:

Пароль:

Запомнить

Регистрация позволит Вам пользоваться дополнительными сервисами.
Сейчас на сайте:
Гостей: 236
Пользователей: 0

Статьи:: Delphi :: Разные статьи :: Шаблоны в Object Pascal



отправить ссылку другу версия для печати  Обсудить на форуме

Шаблоны в Object Pascal



Наверное каждый Delphi программист хоть раз общался с программистом C++ и объяснял насколько
Delphi мощнее и удобнее. Но в некоторый момент, программист C++ заявляет примерно следующее
"OK, но Delphi использует Pascal, а значит не поддерживает множественное наследование и шаблоны,
поэтому он не так хорош как C++."

Насчёт множественного наследования можно легко заявить, что Delphi имеет интерфейсы, которые
прекрасно справляются со своей задачей, но вот насчёт шаблонов Вам прийдётся согласится, так как
Object Pascal не поддерживает их.

Давайте посмотрим на эту проблему по-внимательней
Шаблоны позволяют делать универсальные контейнеры такие как списки, стеки, очереди, и т.д.
Если Вы хотите осуществить что-то подобное в Delphi, то у Вас есть два пути:

Использовать контейнер TList, который содержит указатели. В этом случае Вам прийдётся всё
время делать явное приведение типов.
Сделать подкласс контейнера TCollection или TObjectList, и убрать все методы, зависящие от типов
каждый раз, когда Вы захотите использовать новый тип данных.
Третий вариант, это сделать модуль с универсальным классом контейнера, и каждый раз, когда нужно
использовать новый тип данных, нам прийдётся в редакторе искать и вносить исправления. Было бы
здорово, если всю эту работу за Вас делал компилятор.... вот этим мы сейчас и займёмся!

Например, возьмём классы TCollection и TCollectionItem. Когда Вы объявляете нового потомка TCollectionItem
, то так же Вы наследуете новый класс от TOwnedCollection и переопределяете большинство методов, чтобы
их можно было вызывать с новыми типами.

Давайте посмотрим, как создать универсальную коллекцию шаблонов класса:

Шаг 1: Создайте новый текстовый файл (не юнитовский) с именем TemplateCollectionInterface.pas:

_COLLECTION_ = class
 (TOwnedCollection)
protected

 function
  GetItem (const aIndex : Integer) : _COLLECTION_ITEM_;
 procedure
 SetItem (const aIndex : Integer;
                    const
 aValue : _COLLECTION_ITEM_);
public

 constructor
 Create (const aOwner : TComponent);

 function
 Add                                 : _COLLECTION_ITEM_;
 function
 FindItemID (const aID    : Integer) : _COLLECTION_ITEM_;
 function
 Insert     (const aIndex : Integer) : _COLLECTION_ITEM_;
 property
 Items      [const aIndex : Integer] : _COLLECTION_ITEM_ read GetItem write SetItem;
end
;

Обратите внимание, что нет никаких uses или interface clauses, только универсальное объявление
типа, в котором _COLLECTION_ это имя универсальной коллекции класса, а _COLLECTION_ITEM_
это имя методов, содержащихся в нашем шаблоне.

Шаг 2: Создайте второй текстовый файл и сохраните его как TemplateCollectionImplementation.pas:

constructor _COLLECTION_.Create (const aOwner : TComponent);
begin

 inherited
 Create (aOwner, _COLLECTION_ITEM_);
end
;

function
 _COLLECTION_.Add : _COLLECTION_ITEM_;
begin

 Result := _COLLECTION_ITEM_ (inherited
 Add);
end
;

function
 _COLLECTION_.FindItemID (const aID : Integer) : _COLLECTION_ITEM_;
begin

 Result := _COLLECTION_ITEM_ (inherited
 FindItemID (aID));
end
;

function
 _COLLECTION_.GetItem (const aIndex : Integer) : _COLLECTION_ITEM_;
begin

 Result := _COLLECTION_ITEM_ (inherited
 GetItem (aIndex));
end
;

function
 _COLLECTION_.Insert (const aIndex : Integer) : _COLLECTION_ITEM_;
begin

 Result := _COLLECTION_ITEM_ (inherited
 Insert (aIndex));
end
;

procedure
 _COLLECTION_.SetItem (const aIndex : Integer;
                                const
 aValue : _COLLECTION_ITEM_);
begin

 inherited
 SetItem (aIndex, aValue);
end
;

Снова нет никаких uses или interface clauses , а только код универсального типа.

Шаг 3: Создайте новый unit-файл с именем MyCollectionUnit.pas:

unit MyCollectionUnit;

interface


uses
 Classes;

type
 TMyCollectionItem = class (TCollectionItem)
     private

      FMyStringData  : String
;
      FMyIntegerData : Integer;
     public

      procedure
 Assign (aSource : TPersistent); override;
     published

      property
 MyStringData  : String  read FMyStringData  write FMyStringData;
      property
 MyIntegerData : Integer read FMyIntegerData write FMyIntegerData;
     end
;

     // !!! Указываем универсальному классу на реальный тип

     
     _COLLECTION_ITEM_ = TMyCollectionItem; 
     
     // !!! директива добавления интерфейса универсального класса


     {$INCLUDE TemplateCollectionInterface}
 

     // !!! переименовываем универсальный класс


     TMyCollection = _COLLECTION_;          

implementation


uses
 SysUtils;

// !!! препроцессорная директива добавления универсального класса


{$INCLUDE TemplateCollectionImplementation}
 

procedure
 TMyCollectionItem.Assign (aSource : TPersistent);
begin

 if
 aSource is TMyCollectionItem then
 begin

  FMyStringData  := TMyCollectionItem(aSource).FMyStringData;
  FMyIntegerData := TMyCollectionItem(aSource).FMyIntegerData;
 end

 else
 inherited;
end
;

end
.

Вот и всё! Теперь компилятор будет делать всю работу за Вас! Если Вы измените интерфейс
универсального класса, то изменения автоматически распространятся на все модули, которые
он использует.

Второй пример
Давайте создадим универсальный класс для динамических массивов.

Шаг 1: Создайте текстовый файл с именем TemplateVectorInterface.pas:

_VECTOR_INTERFACE_ = nterface
 function
  GetLength : Integer;
 procedure
 SetLength (const aLength : Integer);

 function
  GetItems (const aIndex : Integer) : _VECTOR_DATA_TYPE_;
 procedure
 SetItems (const aIndex : Integer;
                     const
 aValue : _VECTOR_DATA_TYPE_);

 function
  GetFirst : _VECTOR_DATA_TYPE_;
 procedure
 SetFirst (const aValue : _VECTOR_DATA_TYPE_);

 function
  GetLast  : _VECTOR_DATA_TYPE_;
 procedure
 SetLast  (const aValue : _VECTOR_DATA_TYPE_);

 function
  High  : Integer;
 function
  Low   : Integer;

 function
  Clear                              : _VECTOR_INTERFACE_;
 function
  Extend   (const aDelta : Word = 1) : _VECTOR_INTERFACE_;
 function
  Contract (const aDelta : Word = 1) : _VECTOR_INTERFACE_; 

 property
  Length                         : Integer             read GetLength write SetLength;
 property
  Items [const aIndex : Integer] : _VECTOR_DATA_TYPE_  read GetItems  write SetItems; default;
 property
  First                          : _VECTOR_DATA_TYPE_  read GetFirst  write SetFirst;
 property
  Last                           : _VECTOR_DATA_TYPE_  read GetLast   write SetLast;
end
;

_VECTOR_CLASS
_ = class (TInterfacedObject, _VECTOR_INTERFACE_)
private

 FArray : array
 of _VECTOR_DATA_TYPE_;
protected

 function
  GetLength : Integer;
 procedure
 SetLength (const aLength : Integer);

 function
  GetItems (const aIndex : Integer) : _VECTOR_DATA_TYPE_;
 procedure
 SetItems (const aIndex : Integer;
                     const
 aValue : _VECTOR_DATA_TYPE_);

 function
  GetFirst : _VECTOR_DATA_TYPE_;
 procedure
 SetFirst (const aValue : _VECTOR_DATA_TYPE_);

 function
  GetLast  : _VECTOR_DATA_TYPE_;
 procedure
 SetLast  (const aValue : _VECTOR_DATA_TYPE_);
public

 function
  High  : Integer;
 function
  Low   : Integer;

 function
  Clear                              : _VECTOR_INTERFACE_;
 function
  Extend   (const aDelta : Word = 1) : _VECTOR_INTERFACE_;
 function
  Contract (const aDelta : Word = 1) : _VECTOR_INTERFACE_; 

 constructor
 Create (const aLength : Integer);
end
;

Шаг 2: Создайте текстовый файл и сохраните его как TemplateVectorImplementation.pas:

constructor _VECTOR_CLASS_.Create (const aLength : Integer);
begin

 inherited
 Create;

 SetLength (aLength);
end
;

function
 _VECTOR_CLASS_.GetLength : Integer;
begin

 Result := System.Length (FArray);
end
;

procedure
 _VECTOR_CLASS_.SetLength (const aLength : Integer);
begin

 System.SetLength (FArray, aLength);
end
;

function
 _VECTOR_CLASS_.GetItems (const aIndex : Integer) : _VECTOR_DATA_TYPE_;
begin

 Result := FArray [aIndex];
end
;

procedure
 _VECTOR_CLASS_.SetItems (const aIndex : Integer;
                                   const
 aValue : _VECTOR_DATA_TYPE_);
begin

 FArray [aIndex] := aValue;
end
;

function
 _VECTOR_CLASS_.High : Integer;
begin

 Result := System.High (FArray);
end
;

function
 _VECTOR_CLASS_.Low : Integer;
begin

 Result := System.Low (FArray);
end
;

function
 _VECTOR_CLASS_.GetFirst : _VECTOR_DATA_TYPE_;
begin

 Result := FArray [System.Low (FArray)];
end
;

procedure
 _VECTOR_CLASS_.SetFirst (const aValue : _VECTOR_DATA_TYPE_);
begin

 FArray [System.Low (FArray)] := aValue;
end
;

function
 _VECTOR_CLASS_.GetLast : _VECTOR_DATA_TYPE_;
begin

 Result := FArray [System.High (FArray)];
end
;

procedure
 _VECTOR_CLASS_.SetLast (const aValue : _VECTOR_DATA_TYPE_);
begin

 FArray [System.High (FArray)] := aValue;
end
;

function
 _VECTOR_CLASS_.Clear : _VECTOR_INTERFACE_;
begin

 FArray := Nil
;

 Result := Self;
end
;

function
 _VECTOR_CLASS_.Extend (const aDelta : Word) : _VECTOR_INTERFACE_;
begin

 System.SetLength (FArray, System.Length (FArray) + aDelta);

 Result := Self;
end
;

function
 _VECTOR_CLASS_.Contract (const aDelta : Word) : _VECTOR_INTERFACE_;
begin

 System.SetLength (FArray, System.Length (FArray) - aDelta);

 Result := Self;
end
;
Шаг 3
: Создайте unit файл с именем FloatVectorUnit.pas:

unit
 FloatVectorUnit;

interface


uses
 Classes;                           // !!! Модуль "Classes" содержит объявление класса TInterfacedObject

type
 _VECTOR_DATA_TYPE_ = Double;       // !!! тип данных для класса массива Double

     {$INCLUDE TemplateVectorInterface}


     IFloatVector = _VECTOR_INTERFACE
_; // !!! give the interface a meanigful name
     TFloatVector = _VECTOR_CLASS
_;     // !!! give the class a meanigful name

function
 CreateFloatVector (const aLength : Integer = 0) : IFloatVector; // !!! дополнительная функция 

implementation


{$INCLUDE TemplateVectorImplementation}


function
 CreateFloatVector (const aLength : Integer = 0) : IFloatVector;     
begin

 Result := TFloatVector.Create (aLength);
end
;

end
.

Естевственно, можно дополнить универсальный класс дополнительными
функциями. Всё зависит от Вашей фантазии!

Использование шаблонов
Вот пример использования нового векторного интерфейса:

procedure TestFloatVector;
 var
 aFloatVector : IFloatVector;
     aIndex       : Integer;
begin

 aFloatVector := CreateFloatVector;

 aFloatVector.Extend.Last := 1
;
 aFloatVector.Extend.Last := 2
;

 for
 aIndex := aFloatVector.Low to aFloatVector.High do
 begin

  WriteLn (FloatToStr (aFloatVector [aIndex]));
 end
;
end
.

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

Комментарии и вопросы присылайте по адресу rossen_assenov@yahoo.com!



Рубрика: Разные статьи




Подгрузка через AJAX HTML-кода, содержащег....

AJAX

При разработке CMS S.Builder наша команда активно использовала AJAX. Теперь вот решили поделиться накопленным опытом. Начнем с этого хабратопика. Не буду здесь затрагивать различные фреймворки и библиотеки. Свой код всегда роднее. Для работы с AJAX-ом в S.Builder написана библиотека sbAJAX. Можете качать и пользоваться :). В этом файле есть функция sbEvalJS. Для тех, кто не знает, объясню. При подгрузке через AJAX и вставке на страницу HTML-кода, содержащего JavaScript, JavaScript выполняться не будет или полезут баги. Эта функция как раз решает поставленную задачу.


Подробнее... | Рубрика: AJAX | Добавлено: 19.11.2008

Обзор нового релиза самой мощной Ajax библ....

AJAX

Хотя наш обзор немного запоздал, оригинальный Dojo 1.2 вышел в релизной версии ещё 6-го октября, но сейчас мы наверстаем упущенное. И так, Dojo Toolkit — это самая мощная и гибкая ajax-библиотека из всех, что есть на рынке, она активно развивается и имеет большое комьюнити. Кстати, это самое комьюнити, совместно с компанией Sitepen, имеет ещё несколько проектов, среди которых и Cometd и некоторые другие, не менее интересные, о которых мы скоро вам расскажем. Сегодня же все внимание на флагманский продукт — Dojo 1.2.


Подробнее... | Рубрика: AJAX | Добавлено: 19.11.2008

Firebug 1.3 и 1.4 alpha — что нового и инт....

Вебмастеру

Если вы профессиональный веб-разработчик и постоянно имеете дело с разработкой и отладкой сложных AJAX приложений, то наверняка знаете и используете Firebug — плагин для браузера Firefox, предназначенный для отладки и исследования веб-приложений. Текущая его версия, 1.2х достаточно стабильная и функциональна, чтобы помочь в 99% проблем, которые могут возникнуть при разработке. Но и этот инструмент не лишён если не недостатков, то некоторых фич, которые могли бы облегчить работу. И даже идеальный инструмент можно сделать ещё более идеальным, как бы это не звучало.


Подробнее... | Рубрика: Вебмастеру | Добавлено: 19.11.2008

Остальные статьи:

Релиз Microsoft Silverlight 2.0. Что новог...
XML документация в C#
Курсоры в MySQL 5
Microsoft опубликовала подробности о сесси...
Microsoft делится подробностями о том, что...
Тестируем новый javascript от нового брауз...
MySQL Query Cache
Использование провайдеров компиляции в As...
Чего мы ждем от C# 4.0
Delphi 2009 и C++Builder 2009
Джоэл Спольски и Джеф Этвуд запустили новы...
Поиск кода Google /* что нового? */
10 jQuery скриптов для улучшения интерфейс...
Генераторы отчетов FastReport 4 и QuickRep...
День программиста — набор стерeотипов
Индусские програмисты
Вышел Django 1.0
Портативная версия Google Chrome Portable
Исходные коды .Net Frameword 3.5 SP1 для о...
Пишем правильный online WYSIWYG-редактор


Цитата дня (все,добавить):

Портал фрилансеров

работа на дому


    Рубрикатор

Программирование

C/С++
Обучение
Windows API
XAML
Моделирование
Паттерны
Visual Basic 7 .NET
WxWidgets
Функции WinApi
Функции С++
Разработка под Mac OS
Eiffel
Visual Studio 2008
UI дизайн
Алгоритмы
Конкурсные статьи
Turbo Pascal
Visual Studio
CASE-средства
Visual Studio 2005
Без VCL
Delphi
Тех. документация
Тестирование
Software Testing
ООП
TCP/IP
Google Android
Windows Installer
.NET Framework
Драйвера
C# C Sharp
Справка
Проектирование
Информ. системы
Visual Basic
Assembler
Оптимизация кода
Gtk+
Компоненты
Реинжиниринг
Управление проектами
Extreeme programming
Lotus Notes
Алгебраическое проектирование


Интернет технологии

PHP
Perl
ASP
WAP
Cookies
SSI
CGI
Web Servers
VB Script
DNS
CSS
XML
Html
Java Script
Java2ME
Firewall
Flash
.htaccess
Apache
VRML
Протоколы
Поисковые системы
Технология JAVA
Учебник по PHP
Учебник по JavaScript
Учебник по XML
Java Q&A
AJAX
DHTML
XHTML
Dreamweaver
Web 2.0
Python
Вебмастеру
Cisco
Ruby on Rails
Silverlight

Базы данных

Access
InterBase
MySQL
Oracle
ADO .NET
Основы SQL
Учебник по Access 2002
MS
Microsoft FoxPro
Доступ к данным
XML в MS SQL Server 2000
ODBC и MyODBC
Обучение
Caché
DB2
PostgresSQL
Sybase
Теория
Хранилища данных
Безопасность
Реляционные данные
MySQL и mSQL

Остальное:

Разное
Обзоры книг
Безопасность
Графика и дизайн
Юмор
Linux
Фракталы
Microsoft Axapta
Многоядерность
Сети
Microsoft Office
Работа
MS-DOS
Криптография
Графика и игроделание
Новости SDK
Системы защиты
Учебник по AutoCad
CVS
Windows XP
Windows Server 2003
Windows Vista
Windows 7
Мероприятия