SPC Show Chart 探討
在這份文件中,我將再深入探討SPC
Client的中以各種形式呈現Chart的設計模型(OOD Model)。
我的目標是提出一套考慮更為完整的物件導向設計,使得在接下來的實作階段中能夠花最少的力氣以更有效率地完成程式實作,同時仍然能夠保持軟體品質,易於除錯,易於閱讀與維護,以及易於因應軟體的改變(降低軟體的改變的成本與時間)。
當然了,實作之中永遠會有更多煩人的細節,有些細節可能會影響到本次設計的模型架構。但是我們預期此部分的問題可以等待至本設計的核心實作出來後,再以程式重整(Refactoring)的手法來回頭修改(Refine)本次設計的模型架構。
這份文件不會提到任何與使用者介面相關的技術,如果您需要此類的資訊,您應該去查閱Borland
C++ Builder或C/C++程式語言的相關文件。另外這份文件也儘量不去提及與特定程語言相關的論題,僅當實際的設計模型使用到與特定程語言相關的技術時,我才會加以說明。同時我也假定您對設計樣式(Design
Pattern)已具有相當程度的瞭解,所以我也不會對所模型中所引用的設計樣式做過多的細節解釋 ─ 已經有許多的書籍及文章完成這個工作,如果需要的話,您應該先去閱讀這些書籍及文章。
特別聲明:
我已經儘量參考目前所能夠得到的資訊來寫作這份文件,同時我也已盡力維持設計的正確性與一致性,但是其中或許仍有疏漏。如果有任何人發現的話,請不吝告訴我。謝謝!
目前SPC模組有7種Chart,而每一個Chart都必須支援3種呈現方式(On-Line Chart,Off-Line
Chart,以及Report),要如何解決Chart與呈現方式的「配對問題」(7x3)?同時仍保有彈性與擴充性?
1.
將ChartType抽象出來:每一個Chart可以想成ChartDef與ChartType的組合。而當ChartType被決定的同時,很多其他的事物亦同時決定了。
注意:此處的ChartType是抽象類別。
2.
ChartType有HistogramChart,ParetoChart,…等7種 (這裡繪出2種做為代表)。這是一種利用Object
Composition達成C/V的方式。
3.
將ChartDisplay由ChartType分離出來。其具體子類別有OnLineDisplay,OffLineDisplay,及ReportDisplay。注意:此處的ChartDisplay是抽象類別。
4.
定義ChartForm抽象類別。ChartForm物件有責任執行真正的Chart顯示與報表產生的工作。它有3個主要的Methods:
1. showChart()
2. showOffLineChart()
3. showReport()
2. showOffLineChart()
3. showReport()
而ChartForm的子類別理想上應該就是實際的UI物件(例如BCB的TForm物件) ,但是實際上恐怕很難達成此要求,同時又為了增加彈性(實際的UI物件可能會改變),所以我們可以使用Adapter樣式來處理實際的UI物件(見下一步驟)。
5.
完成!!
每個ChartType物件有責任建立出正確的ChartForm物件(Expert樣式)。當ChartDef的display方法被呼叫時,ChartDef物件會將此呼叫委任給其內含的ChartType物件的display方法處理,而ChartType物件的display方法會根據子代類別的override版本來執行(多型),而ChartType物件的display方法其實也是將此呼叫委任給其內含的ChartDisplay物件去處理。而到此處,ChartDisplay物件才會將此呼叫委任給真正執行任務的ChartForm物件。
此處值得注意的地方在於ChartForm的子類別往往只是一個Adapter(或Wrapper),其目的在於使得我們可以以一致的介面處理背後的UI物件(這裡的UI物件即是BCB中的Form物件,而此Form物件上已有QCTools的SPC繪畫元件,但是此Form物件未必會繼承ChartForm)。所以圖中的HistogramChartForm與ParetoChartForm類別即扮演著Adapter的角色。其典型的做法即是使用Object
Composition的方式包裝實際的UI物件(即Form物件),然後將呼叫委任給其所內含的UI物件處理。
1.
這裡的解決方案中如果以C/V
(Commonalities/Variabilities)分析(CVA)的角度來看,ChartDef,ChartType,ChartDisplay,以及ChartForm類別即代表了Commonalities (見下圖),也就是代表一個共同的抽象概念。而Commonality類別的子類別則代表了Variabilities。
這種手法可以讓抽象類別來「封裝」Variation (也就是物件導向所說的「易於修改」),但又能讓系統保持概念上的穩定性。所以請記注一句物件導向的內功心法:「Abstraction
is the key!」
2.
此例多處利用抽象類別封裝具體類別的方式—「封裝」的新觀點。因為具體類別即代表系統中可能變動的部分,所以此符合物件導向中的「Find
What Varies and Encapsulate It!」原則。
3.
封裝行為—「封裝」的另一新觀點。分析問題時不要認為「封裝」只是指「資料隱藏」,而要採用更為廣義的定義—「封裝指封裝任何事物」。此例的哲學即在於「封裝display的行為」。
4.
此例的關鍵處大部分使用Object
Composition而非Class
Inheritance。此亦符合「Favor Object Composition
than Class Inheritance」原則。
5.
Adapter樣式不僅只是用來轉換不同的介面而已!其真正的價值在於讓我們在設計時無須擔心有任何具體類別無法符合我們的模型。因為有了Adapter樣式,我們可以轉換任何介面不符合的類別。