Пример рефакторинга Delphi, включающий элементы управления в предоставлении данных и DataModules с прямым доступом к таблицам БД
-
27-09-2019 - |
Вопрос
Я пытаюсь определить лучший способ рефакторы проекта, над которым я работаю.
Из-за отсутствия хорошего дизайна практически все проект состоит из:
1) Формы, содержащие деловую логику
2) Огромные Datamodules (1 за форму + некоторые дополнительные)
3) Некоторые подразделения, которые содержат общий код (библиотеки)
Нет OOP (кроме некоторых небольших областей), повторное использование кода это на минимальном уровне.
Одной из проблем является также то, что используются элементы управления DataWare, поэтому было очень простым отбросить множество наборов данных + DataSources на Datamodules и ссылку непосредственно в DB в очень сопряженном виде.
В идеале я хотел бы извлечь классы, такие как TCUSTOMER, TEMBOLEEE, чтобы получить Advantage OS-инкапсуляцию и позволить этому возможному созданию нового пользовательского интерфейса в будущем без дублирования всего кода.
Во всяком случае, мой вопрос: как я могу продолжать заниматься динамиками DataAware? Должен ли я реализовать функцию, которая возвращает набор данных, и я связываю DataWAREComponent.dataSource к результату функции?
function TCustomer.LoadByID(aCustomerID: integer): TDataset
?
Решение
Вы связаны с архитектурой Ваша заявка была разработана вокруг. Не пытайтесь бороться с этим. Пусть данные в курсе контроля делают то, что они хороши, синхронизация данных. Если ваши элементы управления уже связаны с их источниками данных, используя DFM, не должно быть проблемой.
То, что вам нужно реформировать, это любые обработчики событий, которые вы привязали к вашим элементам управления. Я предлагаю вам взглянуть на Контроллер контроллера шаблон. Я нашел пример реализации для:
- Asp.net.net.
- .Net богатые клиенты(либо WinForms или WPF)
- Болтовня(Этот пионировал шаблон и предложил метку «контролирующего контроллера)
Хотя есть несколько примеров архитектурных узоров пользовательского интерфейса в Delphi, которые ориентированы на настольные приложения, как правило, о Пассивный взгляд а не контроллер контроллера. Так вот мой взять на него.
Вы захотите начать с определения хотя бы одного интерфейса для каждой формы в вашем приложении. Я говорю хотя бы один Поскольку некоторые формы сложны и могут потребоваться разбиться на несколько интерфейсов.
IProductView = interface
end;
Тогда вы можете внести свою форму.
TProductForm = class(TForm, IProductView)
...
end;
Далее вам понадобится докладчик / контроллер. Это будет обрабатывать все, кроме синхронизации данных.
TProductPresenter = class
private
FView: IProductView;
public
constructor Create(AView:IProductView);
end;
Создайте частное поле в своем классе формы и создайте / освободите презентацию, когда форма создана / освобождается. Используете ли вы конструктор / деструктор формы или события OnCreate / OnDestroy не имеют большого значения.
TProductForm = class(TForm, IProductView)
private
FPresenter: TProductPresenter;
public
constructor Create;
...
end;
implementation
TProductForm.Create
begin
FPresenter := TProductPresenter.Create(self);
end;
Теперь, когда вам нужна форма или один из его контроля, чтобы ответить на событие, делегируйте ответственность перед докладчиком. Позвольте предположить, что вам нужно проверить, что название продукта использует правильную капитализацию.
TProductForm.NameDBEditChange(Sender: TObject);
begin
FPresenter.ValidateName;
end;
Вместо того, чтобы пройти контроль или его текстовое свойство в качестве аргумента, вы подвергаете данные как свойство на интерфейсе ...
IProductView = interface
function GetName:string;
procedure SetName(Value: string);
property Name: string read GetName write SetName;
... и внедрить GetName
и SetName
по форме.
TProductForm.GetName: string;
begin
Result := NameDBEdit.Text;
end;
TProductForm.SetName(Value: string);
begin
NameDBEdit.Text := Value;
end;
Важно разоблачить данные в простейшей возможной форме. Вы не хотите, чтобы ведущий в зависимости от имени продукта хранится в TDBEDIT. Ведущий должен видеть только то, что вы явно позволяете, чтобы он видел через интерфейс. Основное преимущество этого заключается в том, что вы можете изменить форму столько, сколько вы хотите (или заменить его полностью), и до тех пор, пока она придерживается интерфейса, никаких изменений необходимо будет выполнить докладчику.
Теперь, когда вся ваша бизнес-логика была перемещена в ваш докладчик, он будет похоже на класс бога. Ваш следующий шаг будет рефактором, что логика в соответствующие классы, разбитые ответственностью. Когда вы достигаете этой точки, вы находитесь в гораздо лучшей позиции, чтобы попытаться архитектурный редизайн (если вы все еще рассматриваете его).
"Вау! Это похоже на много работы!" Вы могли бы сказать. Вы бы правы (но тогда вы знали, что это будет много работы, прежде чем начнутся). Это не должно быть сделано все сразу. Ни один из этих шагов не меняет поведение логики, где это происходит.
Преимущества
- UI теперь легко изменить
- Бизнес-логика может быть легче протестирована в изоляции
- Может быть реализован постепенно
Недостатки
- Сначала он больше работает, хотя это в конечном итоге компенсируется более удобным кодом позже.
- Не подходит для всех приложений. Для небольших проектов дополнительная инфраструктура может не стоить усилий.
Другие ссылки
- Реализация Delphi модель просмотра ведущей (Пример - это пользовательское управление пользовательским интерфейсом)
- TDD'ing GUI.
- Простое начало с MVP в Delphi для Win32, часть 1, Часть 2
Другие советы
Если нет хорошего дизайна и нет реального OOP в коде, то рассмотрение его сложности, вы должны сначала начать с создания дизайна, описывающей его текущую функциональность. Да, это означает, что вы будете заняты, написав много документации сначала. Но это позволяет расщеплять весь проект в логические / функциональные части, которые вы могли бы использовать для того, чтобы сосредоточиться, когда эта документация закончена. Затем вы можете рефакторировать каждую часть отдельно или, возможно, переписать эти части даже.
Проекты Этот комплекс не всегда практичен для рефакторы. Вы должны вернуться к исходному дизайну (тем самым создаю его, так как у вас нет), а затем посмотрите на свой код и считаете, что быстрее: рефакторинг или переписывание ...