2012-05-12 40 views
0

首先,抱歉如果標題有點混亂。德爾福擴展類

我打算開發一個小型的erp應用程序。這個apllication將使用插件/插件。這個插件可能會添加或擴展基礎應用程序的某些模塊。

例如,我有屬性「id」和「名稱」的TCustomer類。 插件1將添加一個屬性「dateofbirth」。 addon 2會添加一個屬性「balance」和一個方法「GetBalance」。

插件1和插件2不知道對方。插件1可能已安裝,而不是插件2,反之亦然。所以這兩個插件都必須繼承基類的tcustomer類。

問題是兩個插件都安裝好了。我如何在兩個插件中獲得擴展屬性?我也將不得不擴展窗體來添加控件來顯示新的屬性。

可以用delphi完成嗎?達到這個目標的最好方法是什麼?也許你可以指點我一些例子的文章?

感謝和我的英文不好 Reynaldi

+0

你的插件類不應該是TCustomer的後代。 – teran

+0

我的意思是'name'或'id'是_property_,所以使它成爲'TCustomerProperty'。每個屬性都應該有名稱,類型(字符串,數字,日期)和值。當你加載插件時,你應該在'TCustomer'類中註冊loeded屬性,爲此你的'TCustomer'應該擁有'TCustomerPrperty'的集合。如果你要創建插件作爲DLL(也可能用C++或其他語言),那麼使用繼承是不可能的(正如你所說的)。在這種情況下,你應該使用_Interfaces_('ICustomerProeprty')。所以,Iheritance是不是解決這個問題的方式,屬性應該是一個單獨的類 – teran

+0

你可以考慮ORM爲Delphi像這裏:http://stackoverflow.com/questions/2942409/is-there-any-new-orm- for-delphi-2010 – philnext

回答

5

好後悔,因爲你已經知道,你不能有一個以上的插件通過繼承擴展現有類。這會混淆任何應用程序,包括任何程序員處理代碼的問題。您需要的是您的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; 
+0

感謝您的明確樣本。我想這是做到這一點的一種方法,或者也許是唯一的方法。最困難的部分是我想的鬼。爲每個插件添加一個標籤可能不是我認爲的優雅或美麗的方式。我想在運行時使用xml生成所有的gui。或者你有更好還是更簡單的解決方案? – Reynaldi

+0

@Reynaldi:不,我不知道。我所知道的插件通常不擴展現有的類,但增加了全新的功能。在這些情況下,每個插件都有一個單獨的選項卡是可以接受的。在運行時生成GUI也可以使用模板(基於dfm,xaml或html)完成。自動合併來自不同插件的模板雖然是一個挑戰,但我會警惕並讓一位「顧問」手動/視覺地完成。您可以通過一種方式讓插件根據「xxx左邊」或「yyy下面」的主要用戶界面註冊附加控件,並自行處理間距。 –

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,特別是單一責任原則。你的問題直接打破了這個原則:你試圖混合客戶個人信息(如姓名)和會計(如餘額)。如果你的項目成長起來,你很可能會被這樣的設計所困住。

+0

是的,我認爲在這裏使用接口會更好。我不熟悉鴨子打字。它看起來很有趣。你能爲我提供一個簡單的例子嗎? – Reynaldi