There's a lot of talk about model-view-controller, model-view-viewmodel, model-view-presenter and so on these days.
What do you see as the best pattern for use with delphi and non-data aware components?
How do you usually implement it?
There's a lot of talk about model-view-controller, model-view-viewmodel, model-view-presenter and so on these days.
What do you see as the best pattern for use with delphi and non-data aware components?
How do you usually implement it?
IMHO the controller part in the model-view-controller pattern is often kind of overhead for delphi applications due to the event-based nature of such applications. The separation of model and view works just as in any other programming language.
I switched to C# and MVVM model (WPF).
Jokes aside start by looking at Object-Oriented Design forum at Embarcadero.
You could take a look at tiOpf as i see they have some components for building the GUI. There is also InstantObjects, but I don't know if it is still developed.
The main problem with VCL components is that it doesn't support binding to objects/lists. So the solution is to use a virtual Dataset like EzSepcials and data aware components or to use non data aware components and write mediators for the individual components. I should mention Virtual TreeView.
You can use the Model View Presenter pattern in his Passive View variation. Some time ago I wrote a port about it. http://www.danieleteti.it/?cat=18
You can use Model Gui Mediator too (http://www.andypatterns.com/index.php/design%5Fpatterns/model%5Fgui%5Fmediator%5Fpattern/)
I think that typical MVC is not appropriate for delphi applications. I have seen implementations that added so much boilerplate code that it was scary. They had more work with themselves that they had with the problem that they tried to solve.
I have written a MVC framework for delphi, but for now I only use it in my own projects. I do not find it production material yet. It is based on Model and Viewer, the controler is only the connecting tissue between the two.
The model contains or handles the business logic and the viewer is strictly for viewing (GUI). So the flow goes like this:
I have automated this so that when the command is called from view, the corresponding command handler method in the model is automatically called. When the model finishes the changes the view is updated. If there is a method that corresponds to a command name in the view, that method is called, otherwise the general "UpdateView" method is called. Only the data that is changed is passed and only relevant parts of view are updated. If there are multiple views for a model, all are updated. The medium for passing data back and forth is XML for now because it is flexible so there is no problem to pass data of any kind. Yes the performance may suffer in extreme cases, but overall the aproach seems to work. I just have to clean it up so there is as little boilerplate and overhead as possible.
Maybe if there is interest I can blog about the solution and clean it up for production quality.
The purpose of MVC is decoupling. Decoupled systems are clearly much easier to maintain, and arguably easier to develop in the first place. Can you radically change your DB design without affecting your GUI code? Can your GUI completely change without impacting too much on your DB design? Is the consistency of data in the DB independent of the order in which GUI, or form-based events occur? These are the questions that really matter, and MVC is an approach to answering those questions in the positive.
I am not an expert, but I have been burned by these few things in the past:
Attempt to put all explicit references to DB access, and DB-access components inside a data-module. It doesn't matter too much if you err on the side of too many datamodules, but be careful not to put too many non-related DB-access items in the same datamodule (combining code is much easier than separating code).
Though it is very convenient to wire all your DB components up to the main connection/session component at design time (and doing so is one of Delphi's strengths), it is also very useful to be able to explicitly set the connectionString, or session, or connection reference dynamically at runtime, particularly when one wants to use the data-module in a different project, without having to add in the original project's DB connection unit, if one exists.
Do your very best to put as little business logic as possible into your component events. This is a natural extension of not using data-aware components. It is difficult to keep to this because doing it consistently seems like doing extra work, especially in a new project, and you tell yourself you'll just refactor later; of course, you know that's a lie because later never comes.
Point (3) may require an example. There is a huge difference in clarity and maintainability between the following two snippets, though it may not be obvious when one looks at them in isolation, as here:
// "LoadEntries" is (loosely) analogous to the "C" in MVC.
// What happens /inside/ LoadEntries is the Model,
// and button interaction is part of View functionality.
// MyList may also be viewable on screen as part of
// the View.
procedure TForm.Button1Click(Sender: TObject);
begin
MyDataModule.LoadEntriesIntoMyList(MyList); // LoadEntries is the "C" in MVC
end;
instead of
// The "controller" is missing. That omission of the essential
// decoupling mechanism between the model and the view will
// cost you or your company lots of money!
procedure TForm.Button1Click(Sender: TObject);
begin
MyList.Clear;
MyDataModule.qMyData.Open;
while not MyDataModule.qMyData.Eof do
begin
NewItem := MyList.AddNewItem();
NewItem.Blah := MyDataModule.qMyData.Fields['Field1'].Value;
...
MyDataModule.qMyData.Next;
end;
end;
I am currently reading the django book, and their MVC design is really impressive. Any part of the implementation-specific model, view or controller can be replaced by a different system without (significantly) affecting the other two. No doubt other frameworks have similar approaches, but I can't comment on those.