[英]Interface hierarchy design pattern?
我正處於開發具有圖形用戶界面的C ++多平台(移動)應用程序的初期階段。 我正在嘗試找到一種抽象實際UI /窗口實現的好方法。 到目前為止,基本上是我嘗試過的:
我創建了一個界面層次結構
Screen
+Canvas
+Form
+Dialog
Control
+EditBox
+CheckBox
+...
我還有一個Application類,該類基本上使用所有這些接口來實現UI邏輯。 Application類還提供了用於創建UI類實例的抽象工廠方法。
這些接口都有實現。 例如,對於Windows Mobile,Win32Form實現Form,Win32Canvas實現Canvas,Win32Dialog實現Dialog。 如您所見,問題在於實現失去了層次結構,即Win32Dialog不擴展Win32Form。
例如,這在方法Form :: addControl(Control&ctrl)中成為問題。 在Windows Mobile版本的應用程序中,我知道ctrl參數是Win32 ...控件實現之一。 但是由於層次結構丟失了,所以無法知道它是Win32EditBox還是Win32CheckBox,我真的需要知道它們才能在控件上執行任何平台特定的操作。
我正在尋找的是有關如何解決此問題的設計模式。 注意,不需要保留此接口層次結構解決方案,這只是我當前的方法。 我將采用能解決將UI邏輯與幾種不同的UI實現分開的問題的方法。
請不要告訴我使用這個或那個UI庫; 我喜歡從頭開始編寫代碼,而我是出於學習經驗... ;-)
我的一些靈感:
不要從屏幕繼承Form。 它不是“是”房地產。
Screen
Canvas
GUIObject
Form
Dialog
Control
Button
EditBox
CheckBox
...
Panel
更詳細的描述:
屏幕
帆布
GUIObject
形成
對話
控件是不言自明的(面板是內部帶有可選滾動條的控件的區域)。
這應該工作。 然而,如何利用每個平台的特定功能而不破壞該接口的通用性和/或易用性是困難的部分。 我通常嘗試將所有圖形與這些基本類分開,並具有一些特定於平台的“畫家”,可以使用每個基本對象並以特定於平台的方式對其進行繪制。 另一個解決方案是為每個平台使用並行層次結構(我傾向於避免這種情況,但有時需要使用-例如,如果需要包裝Windows句柄)或“功能位”方法。
您可以使用遏制。 例如,實現Dialog
的類將包含Win32Dialog
作為屬性,而實現Form
的類將包含Win32Form
; 對Dialog或Form成員的所有訪問都將委派對包含的類的訪問。 這樣,如果這對您的項目有意義,您仍然可以使Dialog
從Form
繼承。
話雖如此,我發現您的界面設計有些奇怪。 如果我理解正確(我可能還沒有,請糾正我),Dialog從Form繼承,Form從Screen繼承。 問問自己,以驗證此設計: 對話框也是表格嗎? 它也是屏幕嗎? 僅當is-a關系有意義時才應使用繼承。
解決此問題的GOF模式是橋接模式。 Konamiman的答案對此進行了解釋,您使用委派/包含來抽象問題之一。
我花了多年的時間進行手機開發。
我的建議是不要陷入“抽象”陷阱!
這樣的框架比僅在每個平台上實現應用程序要更多的代碼(並且令人討厭,不好玩!)。
抱歉; 您正在尋找樂趣和經驗,我想說有很多有趣的地方可以得到它。
首先,主要問題似乎在於您的“抽象”層中沒有抽象。
實現與操作系統提供的控件相同的控件,僅在其名稱前加上“ Win32”前綴並不構成抽象。
如果您不打算真正簡化和概括該結構,那么為什么還要首先編寫一個抽象層呢?
為了做到這實際上是有用的 ,你應該寫,代表你需要概念的類。 然后在內部將它們映射到必要的Win32代碼。 不要僅僅因為Win32有一個Form
類或Window
類。
其次,如果您需要精確的類型,我想放棄OOP方法,並使用模板。
代替功能
Form::addControl(Control &ctrl)
限定
template <typename Ctrl_Type>
Form::addControl(Ctrl_Type &ctrl)
現在,該函數知道控件的確切類型,並且可以執行所需的任何特定於類型的操作。 (當然,如果必須將控件保存到控件的列表中,則會再次丟失類型信息。但是至少可以進一步傳播類型信息,這可能會有所幫助。
該集合甚至可以存儲諸如boost::variant
對象之類的東西,這將使您甚至可以保留一些類型信息。
否則,如果您要使用OOP路線,則至少要正確進行 。 如果您要將EditBoxes和CheckBoxes都隱藏在一個通用的IControl
接口后面,那應該是因為您不需要確切的類型。 該接口應該是您所需要的。 這就是接口的意義。
如果不遵守該合同,那么如果您一直都在貶低實際類型,那么您良好的OOP層次就是有缺陷的。
如果您不知道要達到的目標,將很難成功。 這樣做的目的是嘗試編寫“ Windows公開的用戶界面的抽象”,但是您什么都沒有做,因為Windows 已經公開了。 如果Windows公開的抽象不符合您的需求,請編寫抽象層。 如果您想要一個不同的層次結構,或者根本不需要層次結構,或者不希望任何形式都是Form或Control的層次結構,那么編寫抽象層是有意義的。 如果只需要“與Win32相同,但使用我的命名約定”的圖層,那是在浪費時間。
因此,我的建議是:從您希望GUI層如何工作開始。 然后擔心如何將其映射到基礎Win32原語。 忘記您曾經聽說過的表單,對話框或編輯框,甚至控件或窗口。 所有這些都是Win32概念。 定義在您的應用程序中有意義的概念。 沒有規則要求GUI中的每個實體都必須從公共Control類或接口派生。 沒有規則必須將所有東西都放置在一個“窗口”或“畫布”中。 這是Windows使用的約定。 編寫一個對您有意義的API。
然后根據可用的Win32原語弄清楚如何實現它。
有趣的問題,所以有幾點想法:
如果要使用特定的控件,那么您使用的是Win32特定的方法,對嗎? 希望您不要在談論up_casting:/
那么,當Win32特定的控制方法可以得到更精確的類型時,又如何將其交給通用對象呢?
您也許可以在這里應用得墨meter耳定律。 與Facade
方法配合使用時效果很好。
這個想法是,您實例化一個Win32Canvas,然后要求畫布添加一個對話框(帶有一些參數),但是您實際上並沒有親自操作該對話框,因此,畫布知道其實際類型並可以執行特定於平台的操作。
如果您想稍微控制一些事情,請讓畫布返回一個Id,您以后將使用該Id定位此特定對話框。
如果canvas從模板(平台上的模板)繼承,則可以緩解大多數常見的實現。
另一方面: Facade
實際上意味着膨脹的界面...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.