我在使用C#編寫的遊戲中碰到過問題。這是一個簡單的基於瓷磚的匹配遊戲,並且問題已經出現,我正試圖通電:在C#中使用GetType/instanceof與替代方案
假設我們有基本瓷磚類型,圓形正方形和菱形,它們都是Tile的子類。我試圖將抽象的「匹配」行爲提取到抽象的Tile方法:canMatchWith(Tile t),而不是將圓圈與圓相匹配。 瓷磚也有兩種方法來添加/刪除他們可以匹配的瓷磚。
所以說我們在遊戲中間有一個圓形的方塊,並且我們有一個提示說:「圓形方塊可以和這個方塊相匹配」。我會穿過所有的圓形瓷磚,並說circleTile.addCanMatchWith(typeof(Square))。在內部,我們有一個List canMatchWith。
然後,我想說「圓形不能再與方塊匹配」,並簡單地說circleTile.removeCanMatchWith(typeOf(Square))。
這是我當前的解決方案,它的工作原理沒有我注意到的性能缺陷(這是一個基於拼貼的匹配遊戲,因此這些類型只能按「移動」而不是逐幀評估)。然而,我腦海中的聲音告訴我,這是一種完成這種行爲的不好方法。所以我有一些替代品:
- 枚舉...每個Tile可以用Tiletype類型變量組成。這將在構造函數中初始化,並設置爲Type.SQUARE for squares,依此類推。然後,每個Tile將有一個List canMatchWith,並且功能與我原來的實現相同。除了在這種情況下,這有點棘手。假設我有一些圈子子類,橢圓形和橢圓形。我希望橢圓能夠匹配只有廣場,但elipses可以匹配所有的圈子,而不是正方形。
這裏的問題是冗餘,我的枚舉現在也會有OVAL和ELIPSE,並且Elipse類會有(CIRCLE,OVAL,ELIPSE TileTypes)作爲它可以匹配的類型。這完全是多餘的,我只想說我可以用類型的「圓」。我想瓷磚可以有TileType baseType和TileType實際類型。
- 某些形式的行爲組合。忘記Tile子類,只給Tiles方法和List的實例變量。然後,在運行時我們可以說someTile.addCanMatch(新的CircleMatchBehavior())。這看起來很愚蠢,因爲我會有一堆班只是說你可以匹配一個特定的形狀。
總之,我試圖完成的是讓多個對象類型能夠與任意數量的不同類型進行交互。問題是,我應該使用什麼類型。在這裏使用GetType可以嗎?枚舉?或者有人會推薦更好的策略?我試圖儘可能普遍,這些瓷磚不應該對其他瓷磚有任何硬編碼的依賴關係,並且必須能夠改變他們可以與之進行交互的人員。假設我製作了一個新的Tile子類,五角形...... Pentagons可以與Squares,Circles和Pentagons匹配。我的實施很簡單,但有些事情告訴我這是一個骯髒的面向對象操作。
我覺得我必須使用Types/Enums,因爲我不是想說thisTile.addCanMatch(Tile someOtherObject)。這太具體了,我希望thisTile能夠匹配所有類的實例的所有圖塊。
我怕我不是不夠熟練設計師提出一個完整的設計給你,但如果沒有的方式圓實際* *的功能差異,橢圓操作,最好讓所有的實例都是'Tile'類,然後設置某種'Behavior'屬性。董事會上的所有圈子都可以共享相同的「行爲」對象,然後當規則改變一個回合時,您可以在該行爲對象上設置更改。如果我瞭解情況,這可能會導致更少的代碼重複。 – Katana314
如果我正確理解你,這有點像我的#2行爲組合。我的恐懼是行爲爆炸。例如,MatchesWithCirclesAndSquaresBehavior。看看我在做什麼?如果有5種類型的瓷磚,則我們有5種選擇1加5選2加5選3加5選4加5選5種行爲組合。這似乎比GetType更糟糕。不過,我可能會誤解你的建議。瓷磚本身可以做任何他們想做的事情,也可以做爆炸動畫等等。這隻有當瓷磚可以與其他瓷磚相匹配時纔會這樣做。 – user2045279
我不是在暗示行爲是一個枚舉或一個不可修改的類。你可以用不同的方式對它進行子類化,但主要是我希望它有一個內部集合來表示它的類型(Circle)和它可以匹配的類型(Square)。然後,您可以以某種面向數據的方式更改它。我絕對同意,任何會導致大量if/else/switch塊的東西都應該避免,以利於良好的對象設置,但是我們也希望避免編寫一個新類來解決一些不太新的行爲變體。 – Katana314