在delphi Pascal中实现MVVM和MVC的最佳实践


10

我是一个Delphi Pascal程序员,我使用最新的Embarcadero delphi XE,并且想利用诸如模型视图控制器和模型视图视图模型之类的设计模式。

但是,关于在Pascal上执行此操作的最佳做​​法,在网络上似乎没有很多。我可以找到的大多数示例都在C#中,并且某些语言功能在pascal中不存在,这意味着我可能必须找到实现这些功能的方法。

我正在尝试从此处修改本文的代码

我将列出我面临的问题

  • 可空类型

Pascal不像C#那样具有可为空的类型,因此我创建了自己的类型。

TNullable<T> = record
    strict private
      fHasValue : boolean;
      fValue : T;
      function GetValue:T;
      procedure SetValue(newValue : T);
    public
      property HasValue : boolean read fHasValue;
      property Value : T read GetValue write SetValue;
      procedure SetToNull;
    end;

在实施部分

function TNullable<T>.GetValue:T;
begin
    if fHasValue then
    begin
        Result := fValue;
    end
    else raise Exception.Create('Value Not Set');
end;

procedure TNullable<T>.SetValue(newValue : T);
begin
    fValue := newValue;
    fHasValue := true;
end;

procedure TNullable<T>.SetToNull;
begin
    fHasValue := false;
end;
  • 获取/设置属性

现在我有了可为空的类型,我可以创建可为空的属性,但是它带有一些代码气味

例如,如果我创建

    TFoo = class
      private
        function GetBar:TNullable<Integer>;
        procedure SetBar(x:TNullable<Integer>);
      public 
        property Bar : TNullable<Integer> read GetBar write SetBar;

在实施部分

function TFoo.GetBar:TNullable<Integer>;
begin
    if **valueExists** then
    begin
        Result.Value := **the value**
    end else
    begin
        Result.SetToNull;
    end;
end;

procedure TFoo.SetBar(x:TNullable<Integer>);
begin
    if X.hasValue then
    begin
        //Store/show value here
    end else
    begin
        //handle null assignment here
    end;
end;

很好,但是在使用这些属性时,我不能只使用

myFoo.Bar.Value:= 1;

我必须用

var 
    myBar : TNullable<Integer>;
begin
    myBar.Value := 1;
    myFoo.Bar := myBar;
end;

这有点麻烦。我想可能对此无能为力。

  • 循环参考

我喜欢将类分为不同的单元。

即: 结构体

保持用户界面与控制逻辑以及模型和数据逻辑层分离。

我可能遇到2个类可以互相引用的情况。尽管在大多数情况下我想避免这种情况,但有时还是需要这样做。

例如

unit u_A;

interface

uses
  u_B
  ;

type 
  TA = class
    public
       Foo : TB;
  end;

implementation

end;

和另一个单位

unit u_B;

interface

uses
  u_A
  ;

type 
  TB = class
    public
       Foo : TA;
  end;

implementation

end;

这段代码已损坏,因为两个类相互包含,并且无法在pascal中完成。在C#中,这不是问题。我能想到的解决方案:1.将两个类都包含在同一个单元中,尽管如果我认为这不适合设计,这是一个问题。2.为B创建另一个父接口并从中继承B,然后绕过它。尽管对于这样一个简单的任务来说这很麻烦。

  • 静态类

Delphi中没有任何静态类,这些对于控制类很有用。

  • 在Delphi中使用的最佳容器类

我目前在Generics.Collections中使用TList和TObjectList,它们是在Delphi XE中引入的,我希望它们是最好的用法,因为delphi 7似乎没有任何好的选择。

我仍在考虑事件处理程序以及那里可能出现的任何问题。也许还有其他一些我尚未想到的问题。

感谢您的任何建议。


我最初在代码审查时问过这个问题,但有人建议我在这里发布。
2014年

Answers:


9

您应该研究Spring4D,因为它已经包含可为空的类型(与您的实现类似,但有一些额外的运算符重载),并且比RTL中的类型更强大。它们也基于接口,这非常方便,因为您不必担心生命周期管理,尤其是在传递它们时。

对于交叉引用问题,我建议针对接口进行编码,并将其用作另一个实现中的参考,而不是两个相互了解的实现。

至于MVVM部分,您可能会研究DSharp,它具有用于Delphi的Caliburn Micro端口的第一个版本。这是一个非常早期的阶段,几乎没有文档记录,但是您可能会获得一些想法,即如何使用松散耦合的GUI和与数据绑定关联的业务逻辑在Delphi中实现MVVM。如果您更感兴趣,Blaise Pascal杂志上有两篇文章。

PS我猜你的意思是您正在使用XE6,因为它是最新版本。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.