0

首先,对不起,如果标题有点混乱。

我正计划开发一个小型 erp 应用程序。此应用程序将使用插件/插件。此插件可能会添加或扩展基本应用程序的某些模块。

例如,我有带有属性“id”和“name”的 TCustomer 类。插件 1 将添加一个属性“dateofbirth”。插件 2 将添加一个属性“balance”和一个方法“GetBalance”。

插件 1 和插件 2 彼此不知道。可能会安装插件 1 而不是插件 2,反之亦然。所以两个插件都必须继承基类 tcustomer 。

问题是两个插件都安装了。如何在两个插件中获得扩展属性?我还必须扩展表单以添加控件以显示新属性。

可以用delphi完成吗?实现这一目标的最佳方法是什么?也许你可以给我一些例子的文章?

感谢并为我糟糕的英语 Reynaldi 感到抱歉

4

2 回答 2

5

好吧,正如您已经知道的那样,您不能有多个插件通过继承来扩展现有类。它会混淆任何应用程序,包括任何程序员处理代码。

您需要的是 TCustomer 类中的某种类型的注册机制,其中每个插件都可以注册其特定属性,或者在创建(初始化)、加载、存储或删除 TCustomer 实例时提供几个回调函数。毕竟,核心 TCustomer 真的不需要了解更多关于插件的信息,而不是它们可能存在的事实。

根据您打算如何加载/存储数据,核心 TCustomer 类甚至不必知道扩展。使持久性机制了解插件并提供一种方法来注册回调函数就足够了,以便在 TCustomer / TOrder / TWhatever 被初始化/加载/保存/删除时调用。

您还必须让 GUI 了解插件并为它们提供注册 UI 片段的方法,以便让主 GUI 为每个插件的特定控件创建一个额外的选项卡或类似的选项卡。

抱歉没有代码示例。我自己还没有实现这个,虽然我考虑过这个设计并且它在我的列表中。

也就是说,为了给您一个想法,基本机制可能如下所示:

TBaseObject = class; // forward declaration

// Class that each plug-in's extensions of core classes needs to inherit from.
TExtension = class(TObject)
public
  procedure Initialize(aInstance: TBaseObject);
  procedure Load(aInstance: TBaseObject);
  procedure Store(aInstance: TBaseObject);
  procedure Delete(aInstance: TBaseObject);
end;

// Base class for all domain classes
TBaseObject = class(TObject)
private
  MyExtensions: TList<TExtension>;
public
  procedure RegisterExtension(const aExtension: TExtension);
  procedure Store;
end;

procedure TBaseObject.RegisterExtension(const aExtension: TExtension);
begin
  MyExtensions.Add(aExtension);
end;

procedure TBaseObject.Store;
var
  Extension: TExtension;
begin
  // Normal store code for the core properties of a class.
  InternalStore; 
  // Give each extension the opportunity to store their specific properties.
  for Extension in MyExtensions do
    Extension.Store(Self);
end;
于 2012-05-12T16:53:28.467 回答
1

这样的“进化”类是某种多继承。

我认为你应该更好地使用接口而不是类。

也就是说,每个插件都将提供一个类实现,但您将使用接口和接口工厂。

请参阅这篇关于“我们为什么需要接口”的文章,或者我们博客中关于接口和与类的比较的这篇文章

您可以测试一个类是否实现了接口:对于像您这样的插件系统,这可能是实现开放实现的最佳方式。鸭打字非常适合插件。整个 Delphi IDE(和 Windows 本身)都在为其插件系统使用接口(通过 COM for Windows)。对于不太强大的实现模式,您可以不使用接口,而是使用后期绑定:请参阅此 SO 问题的答案。

看看SOLID 原则,尤其是单一责任原则。你的问题直接打破了这个原则:你试图混合客户个人信息(如姓名)和会计(如余额)。如果你的项目长大了,你可能会被这样的设计卡住。

于 2012-05-13T15:36:16.520 回答