Delphi扩展类

时间:2012-05-12 14:28:08

标签: delphi

首先,对不起,如果标题有点令人困惑。

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

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

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

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

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

谢谢,抱歉我的英语不好 Reynaldi

2 个答案:

答案 0 :(得分:5)

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

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

根据您打算如何加载/存储数据,核心TCustomer类甚至不必了解扩展。只要TCustomer / TOrder / TWOUT被初始化/加载/保存/删除,就可以让持久性机制了解插件,并为它们提供一种注册回调函数的方法。

您还必须让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;

答案 1 :(得分:1)

这种“不断发展”的阶级是某种多重继承。

我认为你最好使用接口而不是类。

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

请参阅this article about "why we need interfaces"this article from our blog about interfaces and a comparison with classes

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

查看the SOLID principles,尤其是单一责任原则。您的问题直接违反了这一原则:您尝试混合客户个人信息(如姓名)和会计(如余额)。如果你的项目成长,你可能会被这样的设计所困扰。