2012-04-07 8 views
3

Ich schreibe das einfache Kartenspiel "War" für Hausaufgaben und jetzt, da das Spiel funktioniert, versuche ich, es modularer und organisierter zu machen. Unten ist ein Abschnitt von Main(), der den Großteil des Programms enthält. Ich sollte erwähnen, dass der Kurs in C# unterrichtet wird, aber es ist kein C# -Kurs. Stattdessen lernen wir grundlegende Logik- und OOP-Konzepte, damit ich einige C# -Funktionen nicht nutzen kann.Aufrechterhaltung der Modularität in Main()?

bool sameCard = true; 

while (sameCard) 
{ 
    sameCard = false; 
    card1.setVal(random.Next(1,14));  // set card value 
    val1 = determineFace(card1.getVal()); // assign 'face' cards accordingly 
    suit = suitArr[random.Next(0,4)];  // choose suit string from array 
    card1.setSuit(suit);     // set card suit 
    card2.setVal(random.Next(1,14));  // rinse, repeat for card2... 
    val2 = determineFace(card2.getVal());  
    suit = suitArr[random.Next(0,4)];   
    card2.setSuit(suit); 

    // check if same card is drawn twice: 

    catchDuplicate(ref card1, ref card2, ref sameCard); 
} 
Console.WriteLine ("Player: {0} of {1}", val1, card1.getSuit()); 
Console.WriteLine ("Computer: {0} of {1}", val2, card2.getSuit()); 

// compare card values, display winner: 

determineWinner(card1, card2); 

hier sind also meine Fragen:

  • Kann ich Schleifen in Main() und es noch modular in Betracht ziehen?
  • Ist der Kartenzeichnungsprozess richtig geschrieben/enthalten?
  • Wird es als schlechte Praxis angesehen, Nachrichten in einer Methode zu drucken (z. B. determineWinner())?

Ich habe nur für zwei Semester programmiert und ich möchte in diesem Stadium gute Gewohnheiten bilden. Jede Eingabe/Beratung würde sehr geschätzt werden.

Edit:

catchDuplicate() ist nun ein boolean Methode und der Aufruf sieht wie folgt aus:

sameCard = catchDuplicate(card1, card2);

dank @Douglas.

+0

Nicht sicher, ob dies wirklich eine StackOverflow-Frage ist. Dies ist eine Art Best-Practice-Frage, die subjektiv sein kann, aber dazu neigt, einen Konsens zu haben. –

+1

Ändert 'catchDuplicate' jemals die Werte von' card1' und 'card2'? Wenn nicht, dann sollten Sie seine Unterschrift ändern: 'sameCard = catchDuplicate (card1, card2);' – Douglas

+0

@SionSheevok oh in Ordnung, wenn diese bewegt werden sollte wäre ich mehr als glücklich zu. – nvillec

Antwort

3

Kann ich Schleifen in Main() verwenden und immer noch als modular betrachten?

Ja, Sie können. Meistens enthält Main in OOP-Programmen jedoch nur eine Handvoll Methodenaufrufe, die die Kernfunktionalität initiieren, die dann in anderen Klassen gespeichert wird.

Ist der Kartenzeichnungsprozess richtig geschrieben/enthalten?

Teilweise. Wenn ich Ihren Code richtig verstehe (Sie zeigen nur Main), führen Sie einige Aktionen durch, die, wenn sie in der falschen Reihenfolge oder mit den falschen Werten ausgeführt werden, nicht gut enden. Stellen Sie sich Folgendes vor: Wenn Sie Ihre Klassenbibliothek verkaufen (nicht das gesamte Produkt, aber nur Ihre Klassen), was wäre der beste Weg, Ihre Bibliothek für einen nicht initiierten Benutzer zu verwenden?

I.e., betrachte eine Klasse Deck, die ein Kartenspiel enthält. Bei der Erstellung werden alle Karten erstellt und gemischt. Geben Sie ihm eine Methode Shuffle, um das Deck zu mischen, wenn der Benutzer Ihrer Klasse mischen muss und fügen Sie Methoden wie DrawCard für die Behandlung von Karten hinzu.

weiter: Sie haben Methoden, die noch Funktionalität innerhalb einer Klasse für sich nicht enthalten sind, besser in einer Klasse sein würde. Das heißt, ist besser geeignet determineFace Verfahren auf Klasse zu sein Card (card2 vorausgesetzt ist vom Typ Card).

Wird es als schlechte Praxis angesehen, Nachrichten in einer Methode zu drucken (z. B. deatcheWinner())?

Ja und nein. Wenn Nachrichten nur während des Tests angezeigt werden sollen, verwenden Sie Debug.WriteLine. In einem Produktions-Build sind dies No-Ops. Stellen Sie jedoch sicher, dass das aus dem Name der Methode klar ist, wenn Sie Nachrichten in einer Produktionsversion schreiben. Ie., WriteWinnerToConsole oder etwas.

Es ist häufiger nicht tun Sie dies, weil: In welchem ​​Format würden Sie die Informationen drucken? Welcher Text sollte dabei sein? Wie gehst du mit Lokalisierung um? Wenn Sie jedoch ein Programm schreiben, muss es natürlich Methoden enthalten, die Daten auf den Bildschirm (oder das Formular oder die Webseite) schreiben. Diese sind normalerweise in bestimmten Klassen für diesen Zweck enthalten. Hier könnte das zum Beispiel die Klasse CardGameX sein.

Allgemeine Gedanken
über das Prinzip Denken „eine Methode/Funktion nur eine Aufgabe nur und eine Aufgabe haben, und es soll Nebenwirkungen nicht (hat wie Quadrat Berechnung und Druck, dann druckt die Nebenwirkung). "

Das Prinzip für die Klassen ist, auf sehr hohe Niveau: eine Klasse enthält Methoden, die logisch zusammengehören und auf dem gleichen Satz von Eigenschaften/Feldern arbeiten. Ein Beispiel für das Gegenteil: Shuffle sollte keine Methode in Klasse Card sein. Es würde jedoch logisch in die Klasse Deck gehören.

+1

Ich mag diese Antwort wirklich. Danke für die klaren und ausführlichen Erläuterungen! Mein Verständnis von OOP ist bisher begrenzt (meine Klasse bewegt sich gerade aus dem Verfahrensbereich), aber das hat enorm geholfen. – nvillec

3

Wenn das Hauptproblem Ihrer Hausaufgaben eine modulare Anwendung erstellen, müssen Sie alle Logik in spezialisierten Klassen kapseln. Jede Klasse muss nur einen Job ausführen. Funktion, die mit der Karte spielen, muss in einer Kartenklasse sein. Funktion, die Karten zieht, sollte eine andere Klasse sein.

Ich denke, es ist das Ziel Ihrer Hausaufgaben, viel Glück!

+1

Normalerweise, in "Best Practice" -OOP, macht jede Methode nur einen Job. Eine Klasse enthält eine verwandte Gruppe von Jobs, die mit denselben Daten arbeiten (enthalten in Feldern/Eigenschaften). – Abel

+3

+1. Ja, grundsätzlich sollte die 'Main' Methode nur eine Spielklasse instanziieren und das Spiel starten. etwas wie 'var game = new CardsGame(); Spiel.Run(); Console.ReadKey(); '. –

+1

Da die Frage mit ** Hausaufgabe ** markiert ist, müssen wir versuchen, ihm den Weg zu zeigen, nicht seine Hand nehmen und den Weg gehen. Heutzutage sehe ich viele Entwickler, die erst jetzt Rezepte befolgen, nicht programmieren. Ich habe Hoffnung in diesem Padawan. – LawfulHacker

1

Q: Kann ich Schleifen in Main() verwenden und immer noch als modular betrachten?

A: Ja, Sie können Schleifen verwenden, die sich nicht wirklich auf die Modularität auswirken.

F: Ist der Kartenzeichnungsprozess richtig geschrieben/enthalten?

A: Wenn Sie modularer sein wollen, verwandeln Sie DrawCard in eine Funktion/Methode. Vielleicht schreibe DrawCards statt DrawCard, aber dann gibt es dort eine Optimierungs-Modularitäts-Frage.

F: Wird es als schlechte Methode angesehen, Nachrichten in einer Methode zu drucken (zB detenetWinner())?

A: Ich würde nicht sagen, Drucken von Nachrichten in einer Methode ist schlechte Praxis, es hängt nur vom Kontext ab. Im Idealfall behandelt das Spiel selbst nichts außer Spiellogik. Das Programm kann irgendeine Art von Spielobjekt haben und es kann den Status vom Spielobjekt lesen. Auf diese Weise könnten Sie das Spiel technisch von einer textbasierten zu einer grafischen Version ändern. Ich meine, das ist ideal für die Modularität, aber bei einer Deadline ist das vielleicht nicht praktikabel. Sie müssen immer entscheiden, wann Sie eine Best Practice opfern müssen, weil es nicht genug Zeit gibt. Leider ist dies nur allzu oft der Fall.

Separate Spiel Logik von der Präsentation von ihm. Mit einem einfachen Spiel wie diesem ist es eine unnötige Abhängigkeit.

+0

+1 für detaillierte Antworten. Danke für die ausführliche Erklärung! Ich hatte eine "drawCard" -Methode für eine Weile, die die Farbe und die Wertzuweisungen enthielt, und sie für jede Karte aufgerufen. Idealerweise sollte jedoch jede Methode nur für eine Aufgabe verantwortlich sein. Wo ist die Linie gezeichnet, ist "eine Karte ziehen" eine Aufgabe oder wären die einzelnen 'set' Methoden die Aufgaben. Ich denke, was ich noch nicht ganz verstehe, ist was eine einzelne Aufgabe definiert. – nvillec

2

Nehmen Sie alle Ratschläge zu "Best Practices" mit einem Körnchen Salz. Denk immer an dich selbst.

Das heißt:

  • Kann ich Schleifen in Main() und betrachten noch modular es?

Die beiden Konzepte sind unabhängig. Wenn Ihr Main() nur High-Level-Logik (d. H. Ruft andere Methoden), dann ist es egal, ob es in einer Schleife tut, nachdem der Algorithmus eine Schleife erfordert. (Sie würden keine Schleife unnötig hinzufügen, nein?)

Als Faustregel, wenn möglich/praktisch, machen Sie Ihr Programm selbstdokumentieren. Machen Sie es "lesbar", wenn eine neue Person (oder Sie selbst, in ein paar Monaten) es betrachtet, können sie es auf jeder Ebene verstehen.

  • Ist der Kartenzeichnungsprozess richtig geschrieben/enthalten?

Nein. Zunächst einmal sollte eine Karte niemals zweimal ausgewählt werden. Für einen „modularen“ Ansatz würde ich so etwas wie dieses:

while (Deck.NumCards >= 2) 
{ 
    Card card1 = Deck.GetACard(); 
    Card card2 = Deck.GetACard(); 
    PrintSomeStuffAboutACard(GetWinner(card1, card2)); 
} 
  • Ist es schlechte Praxis betrachtet Nachrichten in einem Verfahren zu drucken (dh: determineWinner())?

Ist der Zweck eine Nachricht zu drucken? Wenn die Antwort "Nein" lautet, dann handelt es sich nicht um eine "schlechte Übung", Sie funktionieren einfach falsch.

Das heißt, es gibt so etwas wie ein "Debug" Build und ein "Release" Build. Um Ihnen beim Debuggen der Anwendung zu helfen und herauszufinden, was funktioniert und was nicht, sollten Sie Logging-Nachrichten hinzufügen.

Stellen Sie sicher, dass sie relevant sind und nicht im Build "release" ausgeführt werden.

+0

Danke für Ihre Antworten!Ihre Erklärung des Zwecks der Methode hat die Dinge geklärt. Ich habe vorher Logging-Nachrichten hinzugefügt, um zu sehen, wo im Programm etwas vor sich ging, ich wusste nicht, dass dies eine tatsächliche Übung war, haha. – nvillec

+1

+1 für "Code lesbar machen". @ nvillec: diese und viele weitere Best Practices finden Sie in dem sehr lesenswerten und zugänglichen Buch [The Pragmatic Programmer] (http://www.amazon.com/The-Pragmatic-Programmer-Journeyman-Master/dp/020161622X) . Ein Wahrzeichen, das ich Ihnen sehr empfehlen kann (nicht auf das Veröffentlichungsdatum schauen, _everything_ in dort ist immer noch anwendbar). – Abel

Verwandte Themen