Блог. Двадцать пять лет Делфи-практики
В этом блоге я буду публиковать ответы на вопросы, которые постоянно приходится повторять на форуме.
Здесь можно это сделать более развернуто и спокойно.
Все, что здесь написано, не является истиной в последней инстанции, скорее, это результат моих размышлений над архитектурой проектов, маленьких и больших, которых я сделал на Делфи более дюжины.
Начав с Делфи-2 двадцать пять лет назад, я прошел все версии, испробовал массу технологий, включая работу с БД, с графикой DirectX, связью с серверами и интернетом, разработку на Андроид и IOS, и многое, многое другое.
________________________________________________________________________________ ____
P.S. все, о чем здесь написано, всего лишь измышления из головы.
совпадения с реальными людьми и фактами случайны.
В этом блоге я буду публиковать ответы на вопросы, которые постоянно приходится повторять на форуме.
Здесь можно это сделать более развернуто и спокойно.
Все, что здесь написано, не является истиной в последней инстанции, скорее, это результат моих размышлений над архитектурой проектов, маленьких и больших, которых я сделал на Делфи более дюжины.
Начав с Делфи-2 двадцать пять лет назад, я прошел все версии, испробовал массу технологий, включая работу с БД, с графикой DirectX, связью с серверами и интернетом, разработку на Андроид и IOS, и многое, многое другое.
________________________________________________________________________________ ____
P.S. все, о чем здесь написано, всего лишь измышления из головы.
совпадения с реальными людьми и фактами случайны.
Как правильно сделать форму логина
Как ни странно, но часто создание сценария входа в программу становится довольно сложным препятствием при построении архитектуры приложения у молодых программистов. Давайте попробуем сделать хороший пример. Итак, сначала должен быть сценарий. Вот он. Стартует приложение. Перед показом главной формы мы должны вывести диалог авторизации к кнопками ОК и Отмена Если в диалоге нажать Отмена, то мы сразу выходим из программы Если ОК - то нужно проверить логин пароль. Если все правильно - показать главную форму, если нет - опять показать диалог. Делать это можно двумя способами - в обработчике OnCreate главной формы, и переопределяя конструктор главной формы Более правильный вариант - второй. Поэтому рассмотрим его. Дело в том, что если мы выберем выход из программы, в случае OnCreate главная форма все равно сначала загрузится и только потом мигнет и программа закончится. Нам это не хочется видеть, поэтому - конструктор. Итак. Мы создадим главную форму TMainForm и форму логина TLoginForm. (примечание про AutoCreate https://www.cyberforum.ru/blog... g4873.html) LoginForm - два Label два Edit и две TButton с заполненным ModalResult mrOk и mrCancel соответственно. BorderStyle=bsDialog. Position=poMainFormCenter В MainForm переопределяем конструктор и пишем туда... оп! не плодить простыни в коде! Пишем туда
например, сама проверка пароля у нас будет выполняться в функции LoginCorrect(login,pass:string):boolean; и она ничего вообще не будет знать о форме логина, ибо мало ли откуда к нам придут логин и пароль впоследствии... итого: Кликните здесь для просмотра всего текста
Кликните здесь для просмотра всего текста
вот и все UPD Более жизненный сценарий старта программы я привел здесь |
Всего комментариев 30
Комментарии
-
а я считаю, что форму авторизации лучше показывать ДО создания главной формы, да и мигание этой формочки при неправильном вводе тоже некомильфо. я делаю обычно так
форма авторизацииDelphi 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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
unit Unit2; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TfrmLogin = class(TForm) Button1: TButton; Button2: TButton; edtLogin: TEdit; edtPass: TEdit; procedure Button1Click(Sender: TObject); end; // функция авторизации. ее можно вызывать потом и при работе программы (ну мало ли :)) // проверять результат и принимать решение function Authorized: boolean; implementation {$R *.dfm} // отображение окна авторизации function Authorized: boolean; begin with TfrmLogin.Create(Application) do begin Result:= ShowModal = mrOk; Free; end; end; // DUMP-функция. проверка карректности данных function CheckLogin(const Login,Password: string): boolean; begin Result:= true; end; procedure TfrmLogin.Button1Click(Sender: TObject); begin // click on OK button if CheckLogin(edtLogin.Text,edtPass.Text) then ModalResult:= mrOk else begin ShowMessage('Incorrect!'); edtLogin.Clear; edtPass.Clear; edtLogin.SetFocus; end; end; end.
главный модуль проектаDelphi 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
program Project1; uses Vcl.Forms, Unit1 in 'Unit1.pas' {frmMain}, Unit2 in 'Unit2.pas' {frmLogin}; {$R *.res} begin Application.Initialize; if not Authorized then Exit; // добавим всего одну строчку Application.MainFormOnTaskbar := True; Application.CreateForm(TfrmMain, frmMain); Application.Run; end.
да и код по итогу короче получаетсяЗапись от DenNik размещена 18.08.2017 в 16:41 -
Не факт. Или не обязательно факт.
Попробую аргументировать.
Во-первых, для проверки логина часто нужно подключиться к БД или взять данные из интернета. А настройки подключения считать из файла. Тогда придется и это пихать сюда же. Перебор.
Более жизненный сценарий старта программы я привел здесь
Во-вторых, мигания (по крайней мере у меня) не заметно.
В-третьих, ужасно не люблю вносить правки в DPR.Запись от krapotkin размещена 21.08.2017 в 17:22
Обновил(-а) krapotkin 21.08.2017 в 17:24 -
Запись от DenNik размещена 22.08.2017 в 10:13 -
это старая история. IDE бывало знатно глючила. До сих пор иногда беспричинно портит DPR и PAS
все дело в том, что она пользуется автоматическим парсингом dpr файла
и когда там много ей непонятного, фиг знает, что у нее слетит )
так что да, сугубо личное и субъективное. предрассудки типа не дразнить красной тряпкой черную кошку )Запись от krapotkin размещена 22.08.2017 в 10:32
Обновил(-а) krapotkin 22.11.2017 в 01:33 -
Запись от DenNik размещена 21.11.2017 в 09:58 -
Запись от Mr_Cipa размещена 20.03.2019 в 00:25 -
Запись от krapotkin размещена 20.03.2019 в 07:35 -
Запись от Usaga размещена 20.03.2019 в 09:01 -
Запись от Rius размещена 20.03.2019 в 09:57 -
перебор - это то, что для произведения данного действия потребуется выполнить действия, с ним непосредственно не связанные
например, загрузка настроек программы - это наверное не дело формы логина? а если еще в командной строке какие-то параметры идут, перекрывающие считанные настройки? тогда форма логина и их должна разбирать?
нарушается принцип разделения логики. Этот кусок становится монолитным и непереносимым в другую программу.
Хотя я уже писал выше, что это вполне имеет место быть удобным/юзабельным для Вас, но неудобно/неприемлемо для меня
Я описываю РАБОЧИЙ и довольно сбалансированный концептуально вариант. И нигде не говорю, что он единственно верный...Запись от krapotkin размещена 20.03.2019 в 10:27 -
Запись от Rius размещена 20.03.2019 в 10:49 -
Форма не только не должна настройки разбирать\загружать, но и в сама в базу ходить. Всё это должны делать отдельные модули приложения, а из формы всё это только "пинаться" должно. А значит должно существовать до формы и вообще без неё.
А если для вас возможность из формы логина в базу сходить - перебор, так это показатель того, что у вас уже монолит неповоротливый и никуда не переносимый.Запись от Usaga размещена 21.03.2019 в 11:03 -
ну, то, что вы мне приписываете, вовсе не следует это из моего текста )
главная форма в конструкторе вызывает чужие методы и для разбора и для обращений к базе
я уже писал выше, что просто стараюсь не писать ничего в DPR, потому что единственное место, куда можно переместить всю эту логику - туда.
так что никакого монолита не возникает.
у меня несколько программ используют модули друг друга
соответственно, архитектура вполне себе модульнаяЗапись от krapotkin размещена 21.03.2019 в 12:46 -
Вообще тут явно говорится: правильно вызывать форму логина из конструктора основной формы. Причём метод проверки логина является членом класса основной формы, и в ней же, очевидно (из показываемого) идёт обращение к БД.
Что плохого в коде в dpr? Это, как я понимаю, аналог Program.Main() из C#. Нормальное место для подготовки данных, ещё не требующих показа форм.
В дельфях DI так и не применяется?Запись от Rius размещена 21.03.2019 в 20:01 -
обратите внимание. весь пример здесь умещен в 50 строк. Сознательно. Чтобы речь шла о принципе.
ни о какой БД речи не идет. почему мы не можем проверить логин и пароль например через веб-запрос?
код в dpr делфи пытается автоматически анализировать. и не думаю, чтобы там стоял мощный AI.
А когда ей чего-то не удается, я не верю в стойкость ее алгоритмов. Она и напортить может.
Хотя я абсолютно не возражаю, если опытные программисты будут делать ЭТО в DPR. Но считаю достаточным и разумным компромиссом советовать новичкам делать вот так.
Например, возникнет вопрос, куда помещать компоненты доступа к БД чтобы проверить логин, если он в базе. Вариант с динамическим созданием точно выше среднего уровня. Вариант с глобальным датамодулем, который создается ДО главной формы уже мне не очень нравится. Я как-то люблю сам создавать и хранить нужные мне вещи. Что и делаю иногда в том же конструкторе. А иногда нет.
Есть много различных моментов, которые могут повлиять на выбор стратегии. А эта статья не призвана раскрывать тонкости, тут только объясняется принцип - открывать форму логина, не вкладывая в нее никакой логики. Сделано это потому что 99% всяких интернет - находок делают не так.
Про DI не понял.Запись от krapotkin размещена 21.03.2019 в 20:28 -
Внедрение зависимости (англ. Dependency injection, DI)
Вкратце: создать и считать настройки до формы, распознать все параметры командной строки до формы, передать то и другое в конструктор формы уже готовым к применению.
Компромисс между "новичкам", "правильнее" и "попроще"... ОК.Запись от Rius размещена 21.03.2019 в 20:58 -
Можем проверить и через веб-запрос, только с точки зрения потребителя (формы авторизации) разницы нет вообще никакой.
Ходилки в БД или веб-сервисы и вообще все сервисы создаются до создания формы и внедряются ей в конструктор (DI). К этому моменту все настройки уже разобраны, все параметры командной строки уже распаршены и применены. Какова природа полученного в конструкторе сервиса (БД или веб-сервис) - форме не известно.
Всё это должно работать и без UI. Вот это правильно и именно такое нужно новичкам прививать. А ужимать пример до пятидесяти строк для "упрощения" архитектуры, когда вы пример этой самой архитектуры показываете... Ну вы поняли...Запись от Usaga размещена 22.03.2019 в 08:13 -
Запись от Mr_Cipa размещена 22.03.2019 в 08:26 -
нет в делфи необходимости чего-то "внедрять" ))
создайте объект, ссылку на него используйте, вот и все внедрение. Тогда все в делфи изначально injected )))
дело в том, что в делфи исторически программа практически ассоциирована со своей главной формой, а не с
program XXX;
begin end.
а требовать, чтобы форма логина и пароля была в программе без UI это вы у себя так делайте, радибоха ))
буду ждать ваши простые и доступные статьи как рассказать новичкам о создании микросервисной архитектуры
и я по-прежнему не вижу, откуда взялись обвинения, что ничего не будет работать без UI ? прямо вдруг интересно сталоЗапись от krapotkin размещена 22.03.2019 в 08:47
Обновил(-а) krapotkin 22.03.2019 в 08:56 -
Цитата:А не могли бы вы показать наглядно? Как это с вашей точки зрения должно выглядеть в коде.
Цитата:нет в делфи необходимости чего-то "внедрять" ))
Я не требую форму без UI. Я о том, что весь функционал должен быть работоспособен и переиспользуем без форм и UI. Т.е. никаких завязок на UI быть не должно. Идеальный тест: вызвать метод входа по логину из консоли.
То, что визуальный конструктор начинает ваш путь в разработке приложения с дизайна основной формы не значит, что вы должны слепо ему следовать. WinForms тоже начинается с дизайнера формы. Но что-то это не особо мешает мыслить сервисами и бизнес-логикой, а не историческим мышкованием.
И микросервисы тут причём?Запись от Usaga размещена 22.03.2019 в 12:01
Обновил(-а) Usaga 22.03.2019 в 12:02