2010-04-28 61 views
4

所以我正在爲Java中的數據結構創建可視化。我已經實現了數據結構(二進制搜索樹),但我需要爲包含的節點類添加一些附加功能。就慣例和最佳實踐而言,我應該使用這種附加功能創建節點的子類,還是應該修改我擁有的並在那裏記錄它?更好地擴展一個類或直接修改它?

我的問題類似於要求here,但這有點過頭了。

我知道這對我正在做的事情可能沒有多大關係,所以我更多地將它作爲一般事情來提出。

編輯:我應該更清楚。我的修改實際上並沒有改變原來的實現,而是添加了一些額外的字段(x和y座標加布爾值來設置該節點是否高亮)以及訪問/修改這些字段的函數。此外,我正在使用的節點類別包含在BST實施中

從閱讀您的答案,似乎有兩種情況下都有參數。我同意創建一個單獨的類或接口可能是一般最好的做法。創建另一個類似乎會變得棘手,因爲您仍然需要一種方法將數據從節點中提取出來。我使用的BST實現是通用的,並且在Node類或BST類中本身沒有任何此類功能來返回數據,所以至少我必須添加它。

感謝您的回覆。

+0

http://en.wikipedia.org/wiki/Open/closed_principle – 2010-04-28 17:03:58

回答

11

要回答的問題是,當您不可視化數據結構時,「基本功能」是否有用,甚至是可取的?

你甚至可能根本不想擴展這個類。沒有更多的細節,在我看來,你有一個數據結構可行。你可以創建一個知道如何虛擬化的新類。

也就是說,不是數據結構,而是知道如何可視化自己,你有一個數據結構,另一個知道如何可視化數據結構的類。哎呀 - 你可能會發現它演變成另一個整體類層次結構,因爲你可能需要對隊列,堆棧等進行可視化處理。無論如何,你的二叉搜索樹都沒有。

+0

++完美。每個班級都應該做好一件事情。存儲數據和可視化數據是兩件事。 – 2010-04-28 18:43:30

2

我會說,在爲現有實現添加功能的一般情況下,您應該擴展現有實現而不是修改它。

這是我的推理。如果該節點在二叉搜索樹實現以外的任何地方使用,那麼當您修改它時,您需要找到它用於確保這些地方都不會與您的修改衝突的地方。雖然只是以新方法的形式添加功能通常不會引起問題,但它可能會導致問題。你永遠不知道如何使用一個對象。其次,即使它僅用於二進制搜索樹中,仍然需要確保BST的實現將在您的修改中很好地發揮作用。

最後,如果你確實擴展它,你不必擔心第一點和第二點。並且您可以獲得額外的獎勵,使您的修改始終與最初的實施保持分離。這樣可以更輕鬆地跟蹤您所做的事情並對其進行評論。

+0

我不確定擴展是否適用於所有情況。例如,如果一個樹基類想要在一個被「覆蓋」保護的區域中創建一個新對象,所以你不能用你的類來返回你自己的對象,而是基本上是錯誤的。 – 2010-04-28 16:32:33

+0

@Chris非常真實。那是當它的時候去創造;) – 2010-04-28 16:52:06

3

既然你一般會問,這裏是簡短的回答:它真的取決於的情況。

首先,假定子類具有「IS-A」以及它們的父類的關係。如果你不能說你的新子類是原始類的一種特定類型,那麼你就提出了錯誤的問題,並且應該創建一個新的,不相關的類。

  • 如果新的代碼是密切相關的類的核心目的,並適用於類(例如,全BSTS)的所有成員,它可能是更好的修改。高cohesion很好。
  • 如果您的新代碼與該課程的核心目的有關,但只與該類型的某些對象(例如,只有平衡的BST)有關,則子類化可能是需要解決的問題。
  • 取決於你改變什麼,你的代碼是多少地方使用,有多少不同的人/組織都在使用它,&角,您的更改可能導致其他代碼意外的行爲,所以你應該三思而後修改現有的代碼。這並不意味着自動劃分常用的東西;由於上述原因,這往往是錯誤的。

在特定情況下,我同意n8wrl;由於可視化與數據結構無關,所以最好實現一個單獨的接口而不是構建一個DrawableBSTNode子類。

0

混合邏輯上獨立的功能將導致一團糟。子類化是一種非常特殊的關係,經常被濫用。子類化用於Is-a-Kind關係。

如果你想要可視化的東西,爲什麼不創建一個完全獨立的類呢?你可以簡單地將你的Node對象傳遞給它。 (甚至更好,使用接口。)

2

有沒有簡單的答案,知道何時以及如何添加功能,你要學會隨時間的東西。

只要添加到基類看起來像簡單的解決方案,但它會污染你的基類。如果這是一個班級,您可以合理地期望使用另一個程序(甚至是您的程序的一部分),那麼您所添加的功能在班級責任的背景下是否有意義?如果不是這可能是一個壞的舉動。你是否添加了鏈接你的基類到你的特定用途的依賴關係?因爲如果你是在窗口外面重複使用代碼。

傳承是解決了很多工程師被吸引到,這是一個誘人的路線。但是隨着我成長爲一名工程師,這是我謹慎使用的一種工具。繼承應該只在真正使用是-A的關係,你需要尊重behavioral subtyping 或者你會後悔以後。而且由於Java只允許單繼承,這意味着你只能在子類型上得到一個鏡頭。

組成(尤其是與接口)通常是一個更好的主意。通常看起來像是 - 一種關係真的是一種 - 一種。或者有時你真正需要的只是一個助手類,它有許多功能可以將原始類作爲參數。

然而,使用合成有一個問題,想要將這些對象存儲在您的樹中。這裏的解決方案是接口。你不需要一棵存儲節點的樹。你想要有一個可以給你一個節點的接口的對象。

public interface HasNode { 
    public Node getNode(); 
} 

你的節點類是一個HasNode,getNode只是返回這個。你的NodeVisualizer類也是一個HasNode,現在你可以在你的樹中存儲NodeVisualizers。當然現在你還有另外一個問題,你的樹可能包含NodeVisualizers和Node,這樣做不好。另外,當你從樹函數返回一個HasNode時,你必須將它們投向正確的實例,這很難看。你會想爲它使用模板,但這是另一個答案。

相關問題