2009-06-04 104 views
2

你如何編寫對象的特殊情況?管理對象間關係

例如,假設我正在編碼一個RPG - 有N = 5個類。矩陣中有N^2個關係,用於確定角色A是否可以攻擊(或使用M的能力)角色B(現在忽略其他因素)。

我該如何在OOP中編寫代碼而不將特殊情況遍佈整個地方?

另一種方式把它是,我有話也許

ClassA CharacterA; 
ClassB CharacterB; 

if (CharacterA can do things to CharacterB) 

我不知道那裏面發生的事情if語句,而是它是

if (CharacterA.CanDo(CharacterB)) 

或元類

if (Board.CanDo(CharacterA, CharacterB)) 

CanDo函數應該依賴於ClassA和ClassB,還是具有ClassA/ClassB的屬性/修飾符?

回答

1

Steve Yegge有一個真棒有關Properties模式的博客文章,您可以使用它來處理此問題。事實上,他用它寫了一個RPG!

http://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html

你可能會說PLAYER1是type1和type1s可以攻擊type2s和player2是第二類型,因此,除非有一些具體PLAYER1「覆蓋」,PLAYER1可以攻擊player2。

這使得非常強大和可擴展的行爲。

1

「see」的定義是什麼?如果他們佔據同一個廣場?如果是這樣,這將在你如何實現碰撞檢測(或在這種情況下的任何情況)而不是字符之間的OOP關係中得到解答。不知道更多的信息,我將接近這樣的問題(圖中C++ /僞代碼):

class Character { 
private: 
    matrixSquare placement; 
public: 
    Character() {}; 
    ~Character {}; 
    matrixSquare getLocation() { return placement;}; 
}; 

class GameBoard { 
private: 
    //your 5 x 5 matrix here 
public: 
    GameBoard() {}; 
    ~GameBoard() {}; 
    boolean isOccupied(matrixSquare) 
    { 
     if (occupied) 
     { 
      //do something 
      return true; 
     } 
     else 
     { 
      return false; 
     } 
    } 
}; 

這裏的竅門是定義你的性格件和你的比賽場地實現之間的關係。在建立之後,您可以澄清如何確定兩個角色是否在同一個正方形中,相鄰的正方形等等......希望有所幫助。

+0

對不起,字面上「看」 - 說一個巫師對狼人是不可見的。 – Timmy 2009-06-04 04:32:40

+0

在這種情況下,有特殊情況是不可避免的。它可以通過一個規則集來緩解,這個規則集存儲在一個表,哈希集合中,但是當它完成所有的說明和完成時,程序必須在某個地方引用A類> B類或者具有不同的能力和能力,等等...... – 2009-06-04 04:34:40

1

我會說使用設計模式,通常我認爲Observer,Mediator和Visitor模式對管理複雜的對象間關係非常有用。

1

我會(假設C++)給每個類一個std::string標識符,由類的實例上的getter方法返回,並使用std::map< std::pair<std::string, std::string>, ... >來編碼類間關係的特殊情況,所有類都很好,並且在一個地方排序。我也可以通過getter函數完全訪問該地圖,以便更改用於編碼部分或全部特例的策略,這很容易。例如:如果只有25對中的幾個類具有「不可見性」屬性,那麼這種情況下的映射可能只包含少數幾個具有該屬性的異常(對於像這樣的布爾屬性,std::set實際上可能是更好的實現,在C + _中)。

一些面嚮對象語言具有多分派(Common Lisp和Dylan是目前想到的兩個),但對於缺乏它的所有(絕大多數)語言來說,這是一個好方法(在某些你會發現一個集中的map/dict是限制性的,並且重構爲Dynamic Visitor設計模式等,但是由於「getter函數」,這些重構對於所有其他代碼都是非常透明的)。

1

爲了迴應您對問題的編輯,您需要查看多態性。我個人認爲Cando()職能是董事會的一部分,然後,根據通過的兩個職業類別,董事會將調用適當的職能並返回結果(戰鬥,看到,等等) 。

如果你在java中這樣做,一個枚舉/接口將與你的遊戲板一起工作,這將是解決這個問題的一個非常乾淨的方法。

3

我會從一個canSee(怪物怪物)或canBeSeenBy(怪物怪物)方法開始,看看會發生什麼。您可能會以Visibilility類結束,或者最終使用http://en.wikipedia.org/wiki/Visitor_pattern。一個極端的例子是叔叔鮑勃三次調度:

// visitor with triple dispatch. from a post to comp.object by robert martin http://www.oma.com 
/* 
In this case, we are actually using a triple dispatch, because we have two 
types to resolve. The first dispatch is the virtual Collides function which 
resolves the type of the object upon which Collides is called. The second 
dispatch is the virtual Accept function which resolves the type of the 
object passed into Collides. Now that we know the type of both objects, we 
can call the appropriate global function to calculate the collision. This 
is done by the third and final dispatch to the Visit function. 
*/ 
interface AbstractShape 
    { 
    boolean Collides(final AbstractShape shape); 
    void Accept(ShapeVisitor visitor); 
    } 
interface ShapeVisitor 
    { 
    abstract public void Visit(Rectangle rectangle); 
    abstract public void Visit(Triangle triangle); 
    } 
class Rectangle implements AbstractShape 
    { 
    public boolean Collides(final AbstractShape shape) 
     { 
     RectangleVisitor visitor=new RectangleVisitor(this); 
     shape.Accept(visitor); 
     return visitor.result(); 
     } 
    public void Accept(ShapeVisitor visitor) 
     { visitor.Visit(this); } // visit Rectangle 
    } 
class Triangle implements AbstractShape 
    { 
    public boolean Collides(final AbstractShape shape) 
     { 
     TriangleVisitor visitor=new TriangleVisitor(this); 
     shape.Accept(visitor); 
     return visitor.result(); 
     } 
    public void Accept(ShapeVisitor visitor) 
     { visitor.Visit(this); } // visit Triangle 
    } 

class collision 
    { // first dispatch 
    static boolean Collides(final Triangle t,final Triangle t2) { return true; } 
    static boolean Collides(final Rectangle r,final Triangle t) { return true; } 
    static boolean Collides(final Rectangle r,final Rectangle r2) { return true; } 
    } 
// visitors. 
class TriangleVisitor implements ShapeVisitor 
    { 
    TriangleVisitor(final Triangle triangle) 
     { this.triangle=triangle; } 
    public void Visit(Rectangle rectangle) 
     { result=collision.Collides(rectangle,triangle); } 
    public void Visit(Triangle triangle) 
     { result=collision.Collides(triangle,this.triangle); } 
    boolean result() {return result; } 
    private boolean result=false; 
    private final Triangle triangle; 
    } 
class RectangleVisitor implements ShapeVisitor 
    { 
    RectangleVisitor(final Rectangle rectangle) 
     { this.rectangle=rectangle; } 
    public void Visit(Rectangle rectangle) 
     { result=collision.Collides(rectangle,this.rectangle); } 
    public void Visit(Triangle triangle) 
     { result=collision.Collides(rectangle,triangle); } 
    boolean result() {return result; } 
    private boolean result=false; 
    private final Rectangle rectangle; 
    } 
public class MartinsVisitor 
    { 
    public static void main (String[] args) 
     { 
     Rectangle rectangle=new Rectangle(); 
     ShapeVisitor visitor=new RectangleVisitor(rectangle); 
     AbstractShape shape=new Triangle(); 
     shape.Accept(visitor); 
     } 
    }