Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
реализация на delphi (но это наверно не важно с точки зрения ооп) Проблема: существует протребность выделения отчетов в отдельный модуль. в настоящее время вызовы и код формирования отчетов размазан по всему коду. Перед выводом отчета на экран (принтер) индивидуально для каждого отчета выполняется некоторый набор действий, для каждого отчета разные. Задача: Сделать модуль требующий минимального программного вмешательства для добавления нового отчета (будет применен fast report, так что шаблоны будут хранится отдельно) и это вмешательство не должно влиять на уже работающие отчеты. Расположение шаблонов тоже не должно быть монолитно зашито в прграмму, т.к. первоночально планируется хранить шаблоны на диске рядом с программой, а затем перенести хранение шаблонов в БД и уже по надобности доставать их из БД. Поэтому обращение к шаблонам тоже надо выделять в отдельный кусок. для того чтоб потом можно было передалать обращение. Первое решение: 1. создать класс report 2. для каждого отчета внутри класса создать функцию xxxInit, в которую помещать индивидуальный код, который требуется выполнять перед формированием отчета (проверки, подготовка данных, и т.п.). Ограничить доступ к функции только внутри класса. 3. для каждого отчета создать общедоступную функцию с требуемыми параметрами. при вызове которой формируется отчет, либо возвращается код ошибки. Но помоему вместо кода ошибки лучше выдавать внятное сообщение пользователю, непосредственно в процедуре xxxInit при проверке. 4. Обращение к шаблону делать через отдельную функцию, в функцию передается константа, однозначно определяющая шаблон, возвращается путь к шаблону. при переносе шаблона в бд в этой функции можно будет реализовать выгрузку шаблона во временный файл на диск. 5. ввести константы для каждого шаблона 6. Ввести перечеслимый тип содержащий константы шаблонов для передачи в функцию обращения к шаблону (п.4) Вопросы: 1. помогите, покритикуйте, может у кого будет предложение на более оптимальную модель. 2. куда еще "сходить", на какие форумы по ООП, где можно подобную тему обсудить и получить советов. Спасибо. P.s. Спасение есть во множестве советов. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.06.2005, 12:23 |
|
||
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
Soldatреализация на delphi (но это наверно не важно с точки зрения ооп) важно всё :) Сразу вопрос - что предсавляет из себя шаблон ? Как програмно осуществляется рабооа с шаблоном ? На первый поверхностный взгляд такое предложение: интерфес IReport +init() +print() - все реальные отчёты его реализуют. Фабрика отчётов: ReportFactory +Report* createReport(IDType id); - создаёт отчёты по некоторому идентификатору. Можно регистрировать некоторые прототипы реализаций в ReportFactory и делать отчёт по прототипу ReportFactory +registerPrototy(Report* r); +Report* createReport(IDType id) { Report *r = prototypes(id); return r->clone(); } в этом случае в фабрику вообще не требуется вносить никаких изменений при добавлении нового типа отчёта. На С++ также можно хорошо разрулить через фабрику, определённую через список создаваемых ей типов, как это реализовать на дельфе не знаю. Интерфейс IReportTemplate + что-то... Если для каждого отчёта надо уметь из общего кода устанавливать некоторые параметры то придётся добавить в IReport что-то типа setProperty(string propertyName, variant val) variant getProperty(string propertyName) для более адекватных советов нужно больше конкретики ;) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.06.2005, 13:30 |
|
||
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
Вот немного из работающего проекта. Правда, сам проект изначально проектировался как отдельный от всего - т.е. программист клепает отчеты из каких надо БД, дает права, пользователи их смотрят. Тебе, я думаю, интереснее всего будет файл uCustomReport.pas - там как раз структура отчета. Хотя не вся - дополнительно в TCustomReport.AdditionalData сохраняюся настройки грида (DevExpress QuantumGrid) и FastReport-а. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.06.2005, 13:42 |
|
||
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
Интегратор Soldatреализация на delphi (но это наверно не важно с точки зрения ооп) важно всё :) Сразу вопрос - что предсавляет из себя шаблон ? Как програмно осуществляется рабооа с шаблоном ? ... для более адекватных советов нужно больше конкретики ;)попытаюсь внести больше конкретики: 1. Шаблон представляет из себя специальный файл, который понимает компонент библиотеки fast report. В шаблоне находятся все ссылки (обращения) к БД и "косметика" позиционирование элементов и т.п. при выводе отчета происходит загрузка необходимого шаблона и вызов функции генерации отчета. 2. Есть множество отчетов, следовательно и множество шаблонов. перед формированием отчета необходимо проверять некоторые условия (например счет не может быть распечатан без указания хотябы одного элемента и т.п. конкретно для гаждого отчета) поэтому и нужна процедура предварительной подготовки отчета, для каждого своя. 3. До вызова генерации отчета, все данные, на которые ссылается отчет должны быть доступны для чтения. Если еще что то непонятно, спрашивайте а я пока попытаюсь осмыслить то что предложили. :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.06.2005, 13:49 |
|
||
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
Soldat Интегратор Soldatреализация на delphi (но это наверно не важно с точки зрения ооп) важно всё :) Сразу вопрос - что предсавляет из себя шаблон ? Как програмно осуществляется рабооа с шаблоном ? ... для более адекватных советов нужно больше конкретики ;)попытаюсь внести больше конкретики: 1. Шаблон представляет из себя специальный файл, который понимает компонент библиотеки fast report. В шаблоне находятся все ссылки (обращения) к БД и "косметика" позиционирование элементов и т.п. при выводе отчета происходит загрузка необходимого шаблона и вызов функции генерации отчета. 2. Есть множество отчетов, следовательно и множество шаблонов. перед формированием отчета необходимо проверять некоторые условия (например счет не может быть распечатан без указания хотябы одного элемента и т.п. конкретно для гаждого отчета) поэтому и нужна процедура предварительной подготовки отчета, для каждого своя. 3. До вызова генерации отчета, все данные, на которые ссылается отчет должны быть доступны для чтения. Если еще что то непонятно, спрашивайте а я пока попытаюсь осмыслить то что предложили. :) Спецификой дельфей не владею кроме давнего опыта работы с Билдером, так что вопрос взаимодейтсвия с дельфовыми компонентами для меня является риторическим :) А так вроде то что изложил - более-менее по-теме вроде :). Если что вам не ясно в такой архитектуре - спрашивайте - либо приводите примеры кода/объяснения как это ложится на вашу задачу ;) PS Кстати с ITemplateReport я маху дал - видимо он не нужен, раз с файлом шаблона работает полностью готовй компонент :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.06.2005, 13:58 |
|
||
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
Интегратор IReport +init() +print() ReportFactory +Report* createReport(IDType id); Из этого следует, что код, индивидуальный для каждого отчета пишится в методе createReport и определяется что выполнять и для кого по ID. Тогда при добавлении нового шаблона и отчета, будет переписыватся головная функция. Интегратор Можно регистрировать некоторые прототипы реализаций в ReportFactory и делать отчёт по прототипу ReportFactory +registerPrototy(Report* r); +Report* createReport(IDType id) { Report *r = prototypes(id); return r->clone(); } я к сожалению не селен в cpp поэтому для меня тоже некоторые термины затруднительны. Что такое прототип реализации? Можно описать на пальцах, без привязки к языку? А то так, на сколько я понял, мне это не подходит. В этой реализации я не вижу места, где можно для каждого конкретного отчета описывать свой код проверки. Согласен, для уневерсальной части, общей для всех отчетов это подходит, а для индивидуальной части где место? ShrВот немного из работающего проекта. Правда, сам проект изначально проектировался как отдельный от всего - т.е. программист клепает отчеты из каких надо БД, дает права, пользователи их смотрят. Тебе, я думаю, интереснее всего будет файл uCustomReport.pas - там как раз структура отчета. Хотя не вся - дополнительно в TCustomReport.AdditionalData сохраняюся настройки грида (DevExpress QuantumGrid) и FastReport-а.Спасибо за щедрый подарок, пытаюсь разобратся, первое впечатление для моей задачи слишком сложно. Пока ничего другого сказать не могу, просто ничего не понятно :( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.06.2005, 17:44 |
|
||
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
Soldat Интегратор IReport +init() +print() ReportFactory +Report* createReport(IDType id); Из этого следует, что код, индивидуальный для каждого отчета пишится в методе createReport и определяется что выполнять и для кого по ID. Тогда при добавлении нового шаблона и отчета, будет переписыватся головная функция. Не следует совсем даже !!! Смотри фабоика в GoF ;) Всё что делает фабрика : это что то типа new ConcreteReport() с соответсвующим типом. я к сожалению не селен в cpp поэтому для меня тоже некоторые термины затруднительны. Что такое прототип реализации? Можно описать на пальцах, без привязки к языку? Постараюсь :) Смотри - ты хочешь уметь создавать разные типы отчётов. При этом весь твой код должен работать только с базовыми абстракным типом. Первый вариант - это для каждого типа написать свой фабричный метод object Factory createReport([in]IdType reportId, [out] Report report) { if (reportId == "SimpleReport") { report = new SimpleReport(); } else if (reportId == "SuperReport") { report = new SuperReport(); } .... } Ну с теми или другими вариациями получится что то подобного типа. Как сделать что бы класс Factory не менялся при добавлении нового отчёта ? Первый вариант - генерить каждый раз новый класс factory с помощью каких-либо языковых средств. Например в С++ это шаблоны. Второй вариант - класс Factory должен содержать список типов, которые он может генерить, тогда при получении запроса на создание отчёта с заданным идентификатором неоьбходиом найти какой ти соотвествует запрашиваему идентификатору и его создать. Для этого необходимо что бы язык поддерживал работу с типами аналогично работе с объектами - это есть например в жабе, но нет в С++, что в дельфе - не знаю :) . Ещё один хороший вариант - держать в ПАфсещкн коллекцию всех объектов которые фабрика может создавать. При чём каждый объект должне уметь создавать свой клон, например через функцию clone(). В этом случае ты находишь по идентификатору объет, который соотвествует этому типу и фабрика просит этот объект отклонировать себя и возвращает опять указатель на бозовый класс. В GoF эти вопросы если не ошибаюсь рассматриваются ;) А то так, на сколько я понял, мне это не подходит. В этой реализации я не вижу места, где можно для каждого конкретного отчета описывать свой код проверки. Согласен, для уневерсальной части, общей для всех отчетов это подходит, а для индивидуальной части где место? Каждый Отчёт реализует функции - print, init и ещё всё что хочешь - то есть каждый отчёт в себе содержит весь код настройки. Ну если я конечно правильно задачу понимаю... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.06.2005, 18:01 |
|
||
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
Интегратор...Кажется я понял. Щас я опишу своими словами как я это понял, ну а вы, если вам еще не надоела эта дискуссия меня поправите если что не так :) Для каждого нового отчета вводится свой тип у каждого отчета есть свой метод init и свой метод print (предположим что других методов пока не надо) практически получаестя что каждый отчет это отдельный класс, раз уж у типа есть методы то это класс, ведь верно? Создается диспетчер или фабрика (название не важно я думаю) которая в зависимости от переданного параметра создает определенный отчет и возвращает ссылку на тип (класс) отчета. После этого мы можем вызывать методы и назначать свойства конкретного отчета. и наконец 3е это "волшебная" раелизация диспетчера (фабрики). Эта реализация должна быть такова, что не зависит от количества существующих реализаций отчетов и работает с неким "надтипом" Следовательно вводится (например) перечеслимый тип, в котором перечислены все уже существующие типы отчетов. Диспетчер при создании очередного отчета выбирает из перечеслимого типа нужный ему тип по переданному индексу и возвращает указатель. При создании нового типа отчета модифицируется перечеслимый тип, и вводится очередная константа, соответствующая этому типу. Похоже на то о чем говорил ты? ИнтеграторСмотри фабоика в GoF ;) А что такое GoF ? ИнтеграторЕщё один хороший вариант - держать в ПАфсещкн коллекцию всех объектов которые фабрика может создавать. А что такое ПАфсещкн ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.06.2005, 11:37 |
|
||
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
Soldat Интегратор...каждый отчет это отдельный класс, раз уж у типа есть методы то это класс, ведь верно? да и наконец 3е это "волшебная" раелизация диспетчера (фабрики). Эта реализация должна быть такова, что не зависит от количества существующих реализаций отчетов и работает с неким "надтипом" приблизительно так... При создании нового типа отчета модифицируется перечеслимый тип, и вводится очередная константа, соответствующая этому типу. Да - вот только фабрика должна уметь создавать экземпляр конкретного класса отчёта - то есть по сути знать о всех отчётах. Фабрика вызывает new YourReport. Как возможный вариант предалагаю что каждый отчёт сам хнает свой идентификатор - например имеет функцию getId() и умеет себя клонировать черезь функцию clone() то есть interface Report +init +getId +clone Тогда фабрика просто находит в своей коллекции зарегистрированных объектов (прототипов) с идентификатором равным запрашиваему, клонирует объект и возвращает ссылку. Таким образом мы возвращаем указатель на реализацию кокретного отчёта через указатель на базовый класс и фабрика вообще не меняется при добавлении нового отчёта ;) Похоже на то о чем говорил ты? ага Смотри фабоика в GoF ;) это ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.06.2005, 13:33 |
|
||
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
Посмотрите это ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.06.2005, 15:34 |
|
||
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
Молодец, Интегратор. Вот здесь использование фабрики классов вполне оправданно. И работать она должна точно так же как в OLE/COM тоесть создавать объекты на основа идентификатора. Только здается мне, что проблема здесь не только и может быть не столько в ООП. Обычно для отчетов используют "чистый" датасет. Тоесть вы производите валидацию данных при вводе, а не отфильтровываете их при формировании отчета. В таком случае неверных типов счетов просто не должно быть в базе. Если же это нормальные сета и вам надо выбрать только специфические, скажем по структуре, то все равно это делается не после формирования датасета, а до в SQL. В этом случае нужды в специальной функции, которая делает специфические вычесления не должно быть. Если вам удастся добиться этого, то, возможно, вы сможете обойтись одним классом, которому вы можете передавать имя файла шаблона в конструкторе( с некоторых пор Делфи поддержывает перегруженные функции и, естественно конструкторы). Есть еще одна идея, которая вам может пригодиться, а может и нет. Сделать отчеты внешними в MS Access. Если вы используете нормальную СУБД MS SQL, Oracle, Informix, Sybase, Interbase и тд. То можно: 1. Создать набов View и пользователя, которому разрешенно только чтение этих View. 2. На клиентах, где создаются отчеты создаете новый ODBC DNS используя права этого пользователя. 3. В access создаете новую базу данных и все татлицы, как присоединенные (linked tables) к тем самым View, которые вы создали в СУБД через DNS. Теперь пользователи могут сами добавлять новые отчеты, какие им только вздумается. Конечно они должны прилично владеть Access-ом. Возможно, этоже можно проделать и с Cristal report. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.06.2005, 14:08 |
|
||
|
ООП: помогите спроектировать простенький класс
|
|||
|---|---|---|---|
|
#18+
AndreiNzТолько здается мне, что проблема здесь не только и может быть не столько в ООП. Обычно для отчетов используют "чистый" датасет. Тоесть вы производите валидацию данных при вводе, а не отфильтровываете их при формировании отчета. В таком случае неверных типов счетов просто не должно быть в базе. Если же это нормальные сета и вам надо выбрать только специфические, скажем по структуре, то все равно это делается не после формирования датасета, а до в SQL. В этом случае нужды в специальной функции, которая делает специфические вычесления не должно быть. Если вам удастся добиться этого, то, возможно, вы сможете обойтись одним классом, которому вы можете передавать имя файла шаблона в конструкторе( с некоторых пор Делфи поддержывает перегруженные функции и, естественно конструкторы). Ну во первых отчет может быть влидным с точки зрения системы и документооборота, но не может иметь печатной копии на данном этапе. Как пример счет введен частично, в биты не все позиции и оператор счет еще на закрыл для редактирования. Он может вернутся к редактированию счета в любой момент. Чисто технически (правила целостности на уровне таблиц и т.п.) такой счет может быть введен, и соответственно его можно вывести на печать, с точки зрения валидности данных они (минимально необходимые данные) могу присутствовать все... Вот примерно для таких случаев и необходима проверка ПЕРЕД формированием отчета. В принципе где она будет реализована это не столь важно. Собственно можно на каждый отчет по функции написать и все. Этот топик был создан с целью найти КРАСИВОЕ решение. Во вторых если ваши базы всегда валидны, то очень за вас рад, и снимаю шляпу. У меня же база без единого правила целосности и т.д. Проверка валдиности на этапе ввода данных практически отсутствует. Класический бардак. Думаю вам приходилось видеть такие базы. AndreiNzЕсть еще одна идея, которая вам может пригодиться, а может и нет. Сделать отчеты внешними в MS Access. Если вы используете нормальную СУБД MS SQL, Oracle, Informix, Sybase, Interbase и тд. То можно: 1. Создать набов View и пользователя, которому разрешенно только чтение этих View. 2. На клиентах, где создаются отчеты создаете новый ODBC DNS используя права этого пользователя. 3. В access создаете новую базу данных и все татлицы, как присоединенные (linked tables) к тем самым View, которые вы создали в СУБД через DNS. Отчеты и так получаются внешними. В формате fastreport. Для редактирования формы отчета пользователем, если возинкнет такая необходимость, можно дать инструмент, на создание которого много времени не уйдет. AndreiNzТеперь пользователи могут сами добавлять новые отчеты, какие им только вздумается. Конечно они должны прилично владеть Access-ом. Возможно, этоже можно проделать и с Cristal report.Не многие пользователи идут на это (добовление новых отчетов). А если они еще будут хорошо владеть инструментальными средствами Cristal report, Access, или SQL, так это уже програмисты получатся :) . В общем цель стоит в написании и дальнейшем КОМФОРТНОМ сопровождении кода. Ладно то что написано, от него никуда не убежишь. А вновь реализовывать или интегрировать генератор отчетов я думаю лишние. На мой взгляд Возможности редактирования шаблона достатончно, а если меняются подребности в данных, сдесь в любом случае без программиста уже дело не обойдется. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.06.2005, 15:04 |
|
||
|
|

start [/forum/topic.php?fid=16&msg=33107493&tid=1347630]: |
0ms |
get settings: |
6ms |
get forum list: |
21ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
135ms |
get topic data: |
11ms |
get forum data: |
2ms |
get page messages: |
64ms |
get tp. blocked users: |
1ms |
| others: | 255ms |
| total: | 501ms |

| 0 / 0 |
