2012-06-13 118 views
4

假設我設計的機器人可以拾取各種工具並使用它們。 我會創建一個具有拾取方法的機器人類來選擇我想使用的工具。 對於每個工具,我都會爲它創建一個類,比如說,具有Cut方法的刀類。 在Robot上調用拾取方法後,我想告訴我的機器人要切割。所以對於OOP概念,我必須告訴機器人,而不是刀? Cut方法在Knife上,所以我怎樣才能調用它?我必須在Robot上實現某種UseToolCurrentlyHeld()以將我的命令傳播給Knife。或者我直接直接用刀(我的機器人持有)直接使用這個:myrobot.ToolCurrentlyInHand.Cut()隱藏父類的實現細節

我覺得這是奇怪的,一個父方法必須有一切照顧他們包含的類。現在我有重複的方法,如刀具有Cut(),現在機器人必須只有UseCutOnKnife()才能在Knife上調用Cut(),因爲良好的面向對象操作是將刀片抽象出來,讓它感覺像訂購機器人一樣,而不用擔心刀片等內部信息。

另一個問題,如果我撰寫音樂,我會創建Music類,其中包含很多Measure類來存儲音符信息。在一個度量中,可以有很多Note類,其中Note類將具有諸如此筆記駐留的度量中的位置或該筆記播放多長時間的信息。現在我想在措施45的中間添加一個備註。要創建測量,我必須在音樂上撥打CreateMeasure(45),然後撥打CreateNote(0.5f)測量?創建的方法是像這樣的父級?如果現在我想將該筆記更改爲0.25度量單位,負責更改方法的筆記是Note類本身或Measure類?或者我必須實施方法來更改最上面的Music類的筆記?

這是我的課的概述:

class Music 
{ 
    List<Measure> measures = new List<Measure>(); 

    //methods... 
} 

class Measure 
{ 
    int measureNumber; 
    List<Note> notes = new List<Note>(); 

    //methods... 
} 

class Note 
{ 
    float positionInMeasure; //from 0 to 1 
} 

由於現在的音樂課上的一切,我現在不得不發行通過音樂的一切的頂部?並且鏈接方法最終調用最內層的類?

+0

+1嗅氣味有些不對勁,和闡明其 – razlebe

回答

5

這裏您需要的是所有工具實現的通用接口。

如:

interface ITool { 
    void Use(); 
} 

現在刀能實現該接口:

class Knife : ITool { 
    public void Use() { 
     //do the cutting logic 
    } 
} 

現在,您將通過機器人上的itool用於接口使用的工具,不知道它是什麼工具:

class Robot { 
    private ITool currentTool = null; 

    public void Pickup(ITool tool) 
    { 
     currentTool = tool; 
    } 

    public void UseTool() { 
     currentTool.Use(); 
    } 
} 

你可以像這樣調用皮卡:

Robot robot = new Robot(); 
robot.Pickup(new Knife()); 
robot.UseTool(); 
+0

+1這正是我的意思:) – davioooh

+0

所以在這種情況下,它就像使用()在刀上與Robot上的UseTool()配對?我的音樂盒怎麼樣?在機器人場景中,刀是直接調用機器人實例創建的。現在爲了創建一個關於度量的新註解,我怎麼能在度量實例中直接調用,知道音樂封裝了它? – 5argon

+0

關於第一個問題:您不必擁有UseTool - 您可以直接調用對currentTool對象的Use。不知道我理解你的第二個問題 –

0

我覺得Action<>可以幫助這裏是關於它的Action and Func一些有用的信息,這幫助我瞭解ActionFunc所以總的來說這是一個偉大的職位。

3

我反而提出了一種不同的方法。有Knife和其他物品的機器人可以選擇從通用類Item繼承與方法Use(也可以是一個接口):

interface Item 
{ 
    void Use(); 
} 

class Knife : Item 
{ 
    public void Use() 
    { 
     // cut action 
    } 
} 

現在每個班級實施Item將有自己的執行Use方法其具體行動。

然後Robot包含通用Item並調用它Use不知道它實際上是什麼:

class Robot 
{ 
    public Item CurrentItem { get; private set; } 

    public void PickUpItem(Item i) 
    { 
     CurrentItem = i; 
    } 

    public void UseItem() 
    { 
     CurrentItem.Use(); // will call Use generically on whatever item you're holding 
    }   
} 

...

Robot r = new Robot(); 
r.PickUpItem(new Knife()); 
r.UseItem(); // uses knife 

r.PickUpItem(new Hammer()); 
r.UseItem(); // uses hammer 
1

基本上,我建議你創建Robot類一種Pickup(Tool tool)方法。 Tool是從中繼承具體工具類的接口。

看看Petar Ivanov的答案。他詳細解釋我的意思。

0

這取決於重點是什麼,告訴機器人使用的東西,或告訴機器人做某件事,或者是兩者,如下所示:

public abstract class Task 
{ 
    public abstract void Perform(Robot theRobot); 
} 

public class Cut : Task 
{ 
    public string What { get; private set; } 

    public Cut(string what) 
    { 
     What = what; 
    } 

    public override void Perform(Robot theRobot) 
    { 
     var knife = theRobot.ToolBeingHeld as Knife; 
     if (knife == null) throw new InvalidOperationException("Must be holding a Knife."); 
     knife.Use(theRobot); 
     Console.WriteLine("to cut {0}.", What); 
    } 
} 

public class Stab : Task 
{ 
    public override void Perform(Robot theRobot) 
    { 
     var knife = theRobot.ToolBeingHeld as Knife; 
     if (knife == null) throw new InvalidOperationException("Must be holding a Knife."); 

     knife.Use(theRobot); 
     Console.WriteLine("to stab."); 
    } 
} 

public class Bore : Task 
{ 
    public override void Perform(Robot theRobot) 
    { 
     var drill = theRobot.ToolBeingHeld as Drill; 
     if (drill == null) throw new InvalidOperationException("Must be holding a Drill."); 

     drill.Use(theRobot); 
     Console.WriteLine("to bore a hole."); 
    } 
} 

public abstract class Tool 
{ 
    public abstract void Use(Robot theRobot); 
    public abstract void PickUp(Robot theRobot); 
    public abstract void PutDown(Robot theRobot); 
} 

public class Knife : Tool 
{ 
    public Knife(string kind) 
    { 
     Kind = kind; 
    } 

    public string Kind { get; private set; } 

    public override void Use(Robot theRobot) 
    { 
     Console.Write("{0} used a {1} knife ", theRobot.Name, Kind); 
    } 

    public override void PickUp(Robot theRobot) 
    { 
     Console.WriteLine("{0} wielded a {1} knife.", theRobot.Name, Kind); 
    } 

    public override void PutDown(Robot theRobot) 
    { 
     Console.WriteLine("{0} put down a {1} knife.", theRobot.Name, Kind); 
    } 
} 

public class Drill : Tool 
{  
    public override void Use(Robot theRobot) 
    { 
     Console.Write("{0} used a drill ", theRobot.Name); 
    } 

    public override void PickUp(Robot theRobot) 
    { 
     Console.WriteLine("{0} picked up a drill.", theRobot.Name); 
    } 

    public override void PutDown(Robot theRobot) 
    { 
     Console.WriteLine("{0} put down a drill.", theRobot.Name); 
    } 
} 

public class Robot 
{ 
    public Robot(string name) 
    { 
     Name = name; 
    } 

    public string Name { get; private set; } 

    public Tool ToolBeingHeld { get; private set; } 

    public void PickUp(Tool tool) 
    { 
     if (ToolBeingHeld != null) ToolBeingHeld.PutDown(this); 

     ToolBeingHeld = tool; 

     ToolBeingHeld.PickUp(this); 
    } 

    public void PutDown() 
    { 
     if (ToolBeingHeld != null) ToolBeingHeld.PutDown(this); 
     ToolBeingHeld = null; 
    } 

    public void Perform(Task task) 
    { 
     task.Perform(this); 
    } 
} 

用法:

var robot = new Robot("Fred the Robot"); 
robot.PickUp(new Knife("butcher")); // output is "Fred the Robot wielded a butcher knife." 

robot.Perform(new Cut("a leg")); // output is "Fred the Robot used a butcher knife to cut a leg." 

robot.Perform(new Stab()); // output is "Fred the Robot used a butcher knife to stab." 

try { robot.Perform(new Bore()); } // InvalidOperationException: Must be holding a drill. 
catch(InvalidOperationException) {} 

robot.PutDown(); // output is "Fred the Robot put down a butcher knife." 
1

對於剛剛機器人例如,在C#中,我將開始是這樣的:

public class Robot 
{ 
    private IList<Tool> tools = new List<Tool>(); 

    public void PickUpTool(Tool newTool) 
    { 
     // you might check here if he already has the tool being added 
     tools.Add(newTool); 
    } 

    public void DropTool(Tool oldTool) 
    { 
     // you should check here if he's holding the tool he's being told to drop 
     tools.Remove(newTool); 
    } 

    public void UseTool(Tool toolToUse) 
    { 
     // you might check here if he's holding the tool, 
     // or automatically add the tool if he's not holding it, etc. 
     toolToUse.Use(); 
    } 
} 

public interface Tool 
{ 
    void Use(); 
} 

public class Knife : Tool 
{ 
    public void Use() 
    { 
     // do some cutting 
    } 
} 

public class Hammer : Tool 
{ 
    public void Use() 
    { 
     // do some hammering 
    } 
} 

所以Robot只需要知道它有工具,但它不一定關心他們是什麼,它肯定不關心他們如何操作。它只是通過標準接口使用它們。這些工具可以包含額外的方法和數據,但它們並不適用於此示例。

1

每個人都給了你一個問題的機器人部分很好的答案。

對於音樂部分,我不確定我會這樣做。特別是,我不會將度量的位置保留在度量本身內,對於註釋及其位置也是如此。另一件我不太喜歡的事情是,你的位置似乎總是絕對值,這對修改現有音樂沒有幫助。也許我在這裏錯過了一些東西,但是當你執行CreateMeasure(45)時會發生什麼,並且音樂中已經有90個測量值了?您必須更新以下所有措施。對於音符位置,我想象你正在使用浮點數,以便能夠表示某種「絕對」位置,即何時播放音符,而不僅僅是它在另一個之後。我認爲我更願意介紹一個持續時間屬性和一個暫停類。最後,我不會將這些方法從Note擴展到Music,但是我會將這些屬性公開,並且您會說我會鏈接方法來最終調用最內層的類。在結束我的班會類似於這些的:

public class Music 
{ 
    public List<Measure> measures = new List<Measure>(); 

    public Measure AddMeasure() 
    { 
     Measure newM = new Measure(); 
     measures.Add(newM); 
     return newM; 
    } 
    public Measure CreateMeasure(int pos) 
    { 
     Measure newM = new Measure(); 
     measures.Insert(pos, newM); 
     return newM; 
    } 
    public Measure CreateMeasureAfter(Measure aMeasure) 
    { 
     Measure newM = new Measure(); 
     int idx = measures.IndexOf(aMeasure); 
     measures.Insert(idx + 1, newM); 
     return newM; 
    } 
    public Measure CreateMeasureBefore(Measure aMeasure) 
    { 
     Measure newM = new Measure(); 
     int idx = measures.IndexOf(aMeasure); 
     measures.Insert(idx, newM); 
     return newM; 
    } 

    //methods... 
} 

public class Measure 
{ 
    public List<ANote> notes = new List<ANote>(); 
    public void AddANote(ANote aNote) 
    { 
     notes.Add(aNote); 
    } 
    public void AddANote(int pos, ANote aNote) 
    { 
     notes.Insert(pos, aNote); 
    } 
    public void AddANoteAfter(ANote aNote, ANote newNote) 
    { 
     int idx = notes.IndexOf(aNote); 
     notes.Insert(idx + 1, newNote); 
    } 
    public void AddANoteBefore(ANote aNote, ANote newNote) 
    { 
     int idx = notes.IndexOf(aNote); 
     notes.Insert(idx, newNote); 
    } 
    //methods... 
} 

public abstract class ANote 
{ 
    public int duration; // something like 4 for a quarter note/pause and so on 
    // your stuff 
} 

public class Note : aNote 
{ 
    float frequency; //or whatever else define a note 
    // your stuff 
} 

public class Pause: aNote 
{ 
    // your stuff 
}