开发者

Delphi: Good pattern/strategy for view <-> model synchronization

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?


You can use the Model View Presenter pattern in his Passive View variation. Some time ago I wrote a post about it. http://www.danieleteti.it/?cat=18

You can use Model Gui Mediator too (http://www.andypatterns.com/index.php/design_patterns/model_gui_mediator_pattern)


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:

  1. 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).

  2. 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.

  3. 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.


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.


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:

  1. In the View something happens (button clicked).
  2. The view sends a command with the associated data to the model
  3. The model makes changes to the business data and prepares the new data for the view
  4. The view is updated with the new data (only a specific section of the view)

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.


I don't use specially MVC or other patterns, but what I do today (while I'm using DB-aware controls for data-synchronization) is to doing something on that way:

  • Each entity form ('entity' in a very loose way, I'm refering the forms that appear first when user clicks on menu itens or buttons) have their Datamodule with their data components.

    • These datamodules, in runtime, get initialized to the application connection (which is another datamodule - global for the application) and that initialization override the connection bound to the datasets on design-time
    • All data manipulations and such, stay in datamodules. The form only does things like DM.SearchCustomers(<conditions>) or DM.SaveData(). Forms doesn't do SQL, period.
    • Entity forms encapsulate the datamodules, so the main application interface just pass the connection to the form and it resend it to the DM.
      • Datamodule creation/destruction are responsibility of the entity form, so normally the DMs are created using the form as owner.
    • Datasources stay in the form in 90% of the situations.

I have a standard form (and datamodule) hierarchy, so most of time simple register (like Payment Methods) forms are made with little or no code.

Delphi lacks (as said above) data binding for objects and most controls are either dataware or complete ignores it.


I see there are some new initiatives in this area.

Stefan Glienke wrote a blog post about MVVM and a delphi library called DSharp back in december 2011.

It now seems like they are trying to implement something similar to Calibrun.Micro for Delphi, which sounds very interesting.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜