德尔福扩展类
首先,抱歉如果标题有点混乱。德尔福扩展类
我打算开发一个小型的erp应用程序。这个apllication将使用插件/插件。这个插件可能会添加或扩展基础应用程序的某些模块。
例如,我有属性“id”和“名称”的TCustomer类。 插件1将添加一个属性“dateofbirth”。 addon 2会添加一个属性“balance”和一个方法“GetBalance”。
插件1和插件2不知道对方。插件1可能已安装,而不是插件2,反之亦然。所以这两个插件都必须继承基类的tcustomer类。
问题是两个插件都安装好了。我如何在两个插件中获得扩展属性?我也将不得不扩展窗体来添加控件来显示新的属性。
可以用delphi完成吗?达到这个目标的最好方法是什么?也许你可以指点我一些例子的文章?
感谢和我的英文不好 Reynaldi
好后悔,因为你已经知道,你不能有一个以上的插件通过继承扩展现有类。这会混淆任何应用程序,包括任何程序员处理代码的问题。您需要的是您的TCustomer类中的某种注册机制,其中每个插件都可以注册其特定属性,或为创建(初始化),加载,存储TCustomer实例时提供几个回调函数,或者删除。核心TCustomer毕竟真的不需要更多地了解插件,而不是它们可能存在的事实。
根据您打算如何加载/存储数据,核心TCustomer类甚至不必知道扩展。使持久性机制知道插件并为他们提供一种注册回调函数的方式就足够了,只要TCustomer/TOrder/TW在初始化/加载/保存/删除时就可以调用该回调函数。
您还必须让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;
感谢您的明确样本。我想这是做到这一点的一种方法,或者也许是唯一的方法。最困难的部分是我想的鬼。为每个插件添加一个标签可能不是我认为的优雅或美丽的方式。我想在运行时使用xml生成所有的gui。或者你有更好还是更简单的解决方案? – Reynaldi
@Reynaldi:不,我不知道。我所知道的插件通常不扩展现有的类,但增加了全新的功能。在这些情况下,每个插件都有一个单独的选项卡是可以接受的。在运行时生成GUI也可以使用模板(基于dfm,xaml或html)完成。自动合并来自不同插件的模板虽然是一个挑战,但我会警惕并让一位“顾问”手动/视觉地完成。您可以通过一种方式让插件根据“xxx左边”或“yyy下面”的主要用户界面注册附加控件,并自行处理间距。 –
这样的“进化”级是某种多继承。
我想你应该更好地使用接口而不是类。
也就是说,每个插件将提供类实现,但您将使用接口和接口工厂。
参见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,特别是单一责任原则。你的问题直接打破了这个原则:你试图混合客户个人信息(如姓名)和会计(如余额)。如果你的项目成长起来,你很可能会被这样的设计所困住。
是的,我认为在这里使用接口会更好。我不熟悉鸭子打字。它看起来很有趣。你能为我提供一个简单的例子吗? – Reynaldi
你的插件类不应该是TCustomer的后代。 – teran
我的意思是'name'或'id'是_property_,所以使它成为'TCustomerProperty'。每个属性都应该有名称,类型(字符串,数字,日期)和值。当你加载插件时,你应该在'TCustomer'类中注册loeded属性,为此你的'TCustomer'应该拥有'TCustomerPrperty'的集合。如果你要创建插件作为DLL(也可能用C++或其他语言),那么使用继承是不可能的(正如你所说的)。在这种情况下,你应该使用_Interfaces_('ICustomerProeprty')。所以,Iheritance是不是解决这个问题的方式,属性应该是一个单独的类 – teran
你可以考虑ORM为Delphi像这里:http://stackoverflow.com/questions/2942409/is-there-any-new-orm- for-delphi-2010 – philnext