涉及Form组件的接口实现如何应用DRY?

How to apply DRY to interface implementations involving Form components?

我有一个接口 IComm 声明一个例程 SetMonitorLogLevel():

unit IFaceComm;
interface
type
  TMonitorLogLevel = (mllOnlyImportant, mllAll);

  IComm = Interface(IInterface)
    procedure SetMonitorLogLevel(LogLevel: TMonitorLogLevel);
  end;

end.

该界面由两个 Form 实现,它们彼此相似,frmBarCommfrmFooComm,如下所示:

TfrmBarComm = class(TForm, IFaceComm.IComm)
  cboDebugLevel: TComboBox;
private
  procedure SetMonitorLogLevel(LogLevel: IFaceComm.TMonitorLogLevel);
end;

请注意,这 2 个 Form 有很多共同的组件,例如 cboDebugLevel,但也可以有另一个 Form 没有的组件。

两种形式以完全相同的方式实现IComm.SetMonitorLogLevel()

procedure TfrmBarComm.SetMonitorLogLevel(LogLevel: IFaceComm.TMonitorLogLevel);
begin
  case LogLevel of
    IFaceComm.TMonitorLogLevel.mllOnlyImportant:
      Self.cboDebugLevel.ItemIndex := 0;
    IFaceComm.TMonitorLogLevel.mllAll:
      Self.cboDebugLevel.ItemIndex := 1;
  end;
end;

如何避免违反“不要重复自己”(DRY) 原则?我经常遇到这个问题,当复制粘贴的例程比我上面显示的简单示例大得多时,它尤其难看。

处理此问题的通常方法是创建另一个实现接口的 class。它可能看起来像这样:

type
  TComboBoxCommImplementor = class(TInterfacedObject, IFaceComm.IComm)
  private
    FDebugLevel: TComboBox;
  public
    constructor Create(DebugLevel: TComboBox);
    procedure SetMonitorLogLevel(LogLevel: TMonitorLogLevel);
  end;

constructor TComboBoxCommImplementor.Create(DebugLevel: TComboBox);
begin
  inherited Create;
  FDebugLevel := DebugLevel;
end;

procedure TComboBoxCommImplementor.SetMonitorLogLevel(
  LogLevel: IFaceComm.TMonitorLogLevel);
begin
  case LogLevel of
    IFaceComm.TMonitorLogLevel.mllOnlyImportant:
      FDebugLevel.ItemIndex := 0;
    IFaceComm.TMonitorLogLevel.mllAll:
      FDebugLevel.ItemIndex := 1;
  end;
end;

然后在您的表单中使用委托实现接口:

type
  TfrmBarComm = class(TForm, IFaceComm.IComm)
    cboDebugLevel: TComboBox;
  private
    FComm: IFaceComm.IComm;
    property Comm: IFaceComm.IComm read FComm implements IFaceComm.IComm
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TfrmBarComm.Create(AOwner: TComponent);
begin
  inherited;
  FComm := TComboBoxCommImplementor.Create(cboDebugLevel);
end;

创建一个框架,该框架拥有在两个窗体上使用的组件。 该框架实现了IComm。两种形式都使用框架,两种形式都实现 IComm。 该框架可作为委托接口实现的 属性 访问。

看起来像这样:

type TfrmBarComm = class(TForm)
  FFrameComm: TFrameComm;
public
  property FrameComm: TFrameComm read FFrameComm implements IComm;
end;