Skapa menyprogram med klasser
Vi tar vårt menyprogram från kmom01 och gör det objektorienterat.
Skapa meny app
Section titled “Skapa meny app”Vi börjar med att skapa vår meny-app i terminalen. Vi ställer oss i kmom02, skapar appens katalog och går ner i den. Därefter skapar vi appen. Nedan visas också kommandot för att köra appen.
dotnet new console -n MenuApp2cd MenuApp2dotnet run // Ger utskriften: Hello, World!"Skapa klasser
Section titled “Skapa klasser”Vi delar upp koden från kmom01 i två klasser, en klass med hjälpmetoder och en klass som presenterar menyn och agerar på de olika menyalternativen. Vi skapar en ny katalog i MenuApp2 och kallar den src som i källkod (source code). De två nya klasserna lägger vi i src.
Klass med hjälpmetoder - Helpers
Section titled “Klass med hjälpmetoder - Helpers”Beskrivning och klassdiagram - Helpers
Section titled “Beskrivning och klassdiagram - Helpers”Helpers är en klass som endast ska innehålla metoder vilka inte är knutna till något objekt. Det finns därför inga medlemsvariabler och klasserna blir statiska.
I klassdiagrammet blir den mellersta rutan tom eftersom det inte kommer att finnas några variabler.
Metoderna som är statiska identifieras genom att de är understrukna i klassdiagrammet.
Implementation
Section titled “Implementation”Vi skapar först klassen Helpers som ska innehålla våra hjälpmetoder. Vi använder “namespacet” eller namnrymden MenuApp2 för att organisera vår kod. Det gör vi för att undvika namnkollisioner och för att göra koden lättare att hantera och underhålla. Vi lägger våra klasser i ett källkodsbibliotek som vi kallar src. Det skapar en ordnad och läsbar kodstruktur som underlättare för utvecklare att arbeta effektivt och lätt förstå projektets struktur.
// stå i kmom02/MenuApp2mkdir srccd srcdotnet new class -n Helpers // funkar inte detta så skapa filen Helpers.cs i VS Codecd .. // gå till rotkatalogen för projektet MenuApp2tree -L 2 // om tree saknas, installera med kommandot sudo apt install tree// Ger följande utskrift:.├── MenuApp2.csproj // projektfilen för MenuApp2├── Program.cs // huvudprogrammet├── src│ ├── Helpers.cs // klassen Helpers├── bin├── objDet går också bra att skapa en tom fil och kalla den Helpers.cs, antingen i VS Code eller i terminalen med touch. Helpers.cs är tom och ser ut så här:
// kmom02/MenuApp2/src/Helpers.csnamespace MenuApp2.src;
public class Helpers{
}Vi lägger till kod i Helpers genom att kopierar metoderna GetTerminalReady, GetRandomNumberFrom10To20, ReadIntFromTerminal och CheckIfAdult från MenuApp (kmom01) och klistrar in dessa. Eftersom detta är en hjälpklass med metoder som ska vara åtkomliga via klassen görs alla metoderna publika.
Uppdatera namespace med MenuApp2.src eftersom det är praxis att namespace ska återspegla filstrukturen.
namespace MenuApp2.src;
public class Helpers{ // Methods public static void GetTerminalReady(string title) { Console.Clear(); Console.Title = title; }
public static int GetRandomNumberFrom10To20() { // Create random class Random random = new Random(); // Get random value from 10 (10 included) up to 21 (21 not included) return random.Next(10, 21); }
public static int ReadIntFromTerminal(string info) { Console.WriteLine("\n" + info); string input = Console.ReadLine() ?? "1";
return int.Parse(input); }
public static string CheckIfAdult(int age) { if (age < 18) { return "Du är inte myndig"; } else { return "Grattis - du är myndig"; } }}Klass med meny - Menu
Section titled “Klass med meny - Menu”Beskrivning och klassdiagram - Menu
Section titled “Beskrivning och klassdiagram - Menu”Klassen Menu skulle kunna vara statisk då den inte kommer behöva variabler men vi väljer att inte göra den statisk för att få ett exempel även på detta.
Implementation
Section titled “Implementation”Då fortsätter vi med att skapa klassen Menu med följande kommandon (terminalen, stå i kmom02/MenuApp2/src):
dotnet new class -n Menu // funkar inte detta så skapa filen Menu.cs i VS Codecd .. // gå till rotkatalogen för projektet MenuApp2tree -L 2// Ger följande utskrift:.├── MenuApp2.csproj // projektfilen för MenuApp2├── Program.cs // huvudprogrammet├── src│ ├── Helpers.cs // klassen Helpers│ └── Menu.cs // klassen MenuMetoderna från koden i kmom01 som hör till menyn, PrintMenu() och Run(), lägger vi i klassen Menu.
namespace MenuApp2.src;
public class Menu{ // Methods private void PrintMenu() { Console.WriteLine("Välj mellan dessa menyalternativ:"); Console.WriteLine("1. Skriv hälsning"); Console.WriteLine("2. Skriv ut en slumptal mellan 10 och 20"); Console.WriteLine("3. Kolla myndighetsålder"); Console.WriteLine("e. Avsluta"); }
public void Run() { // Setup Helpers.GetTerminalReady("MENY"); // anrop direkt på klassen med statiska metoder string choice = "";
while (choice != "e") { PrintMenu(); Console.WriteLine("\nDitt val: "); choice = Console.ReadLine() ?? "";
switch (choice) { case "1": Console.WriteLine("\nHej på dig!\n"); break; case "2": Console.WriteLine("\nRandom value: " + Helpers.GetRandomNumberFrom10To20()); break; case "3": string message = Helpers.CheckIfAdult(Helpers.ReadIntFromTerminal("Vilken är din ålder?")); Console.WriteLine("\n" + message); break; case "e": Console.WriteLine("\nDu har valt att avsluta! Hej då!"); break; default: Console.WriteLine("Ogiltligt menyval"); break; } } }}Huvudprogram
Section titled “Huvudprogram”För att kunna använda meny behöver vi skapa ett Meny-objekt, det vill säga ett objekt av klass-typen Menu. Via objektet anropas metoden Run().
Från och med .NET 6 så ser huvudprogrammet, eller som det också kallas toppnivåinstruktioner (top-level statements), ut så här. Vi kommer att använda detta sätt:
using MenuApp2.src; // Här visar vi att huvudprogrammet använder klassen Menu
Menu myMenu = new Menu();
myMenu.Run();Samma kod i .NET 5 och tidigare versioner ser ut så här:
using System;using MenuApp2.src;
namespace MenuApp2 // Note: actual namespace depends on the project name.{ internal class Program { static void Main(string[] args) { Menu myMenu = new Menu(); myMenu.Run(); } }}För att skapa en app enligt det äldre sättet behöver du skapa en katalog för appen och går ner i den. Därefter skapar du appen med flaggan —use-program-main och du får då den gamla konstruktionen med namespace och class Program. Läs mer om det här.
Resultatet så här långt
Section titled “Resultatet så här långt”Så bra, nu har vi samma resultat som innan. Kör vi programmet med “dotnet run” i terminalen ser det ut så här:
Skriv ut en ascii bild
Section titled “Skriv ut en ascii bild”För att göra menyalternativ 1 lite roligare lägger vi till utskrift av en asciibild efter hälsningen. Det är samma klass som vi kommer att använda i inlämningsuppgiften på nästa kmom. Ladda ner klassen AsciiArt och lägg den i katalogen “kmom02/MenuApp2/src”. Uppdatera namespace till MenuApp2.src.
task download-code -- kmom02/AsciiArt.cscp ../../codeExamples/AsciiArt.cs src/.ls src// ger följande: AsciiArt.cs Helpers.cs Menu.csnamespace MenuApp2.src;
public class AsciiArt{
public static void PrintDie(int diceRoll) { ...I menyalternativ 1 i klassen Menu anropar vi metoden PrintDie i klassen AsciiArt och skriver ut 2 tärningar, i detta exempel har vi argumenten 1 respektive 6.
namespace MenuApp2.src;... switch (choice) { case "1": Console.WriteLine("\nHej på dig!\n"); AsciiArt.PrintDie(1); AsciiArt.PrintDie(6); break;...Om vi kör programmet och väljer menyalternativ 1 ser det ut så här nu:
Lägg till datum och tid
Section titled “Lägg till datum och tid”Klassdiagram Helpers
Section titled “Klassdiagram Helpers”Vi lägger till metoden PrintDateAndTime, som skriver ut olika datum- och tidsinformation till konsolen.
Implementation
Section titled “Implementation”Vi lägger till en ny metod i klassen Helpers. Vi använder DateTime objektet från C# och gör följande:
- skapa ett objekt av klassen DateTime med datum och tid just nu och spara undan det i variabeln
presentTime. Skriv därefter ut datum och tid. - formatera och skriv ut
presentTimeenligt svensk och internationell standard (ISO 8601), så att datumet skrivs på formen år-månad-dag med årtalet i fyra siffror (exempelvis 2024-02-12). - formatera tiden i HH:mm:ss och skriv ut.
- skapa ett objekt 2010-10-23 i variabeln
newTimeskriv ut vilken veckodag det var. - addera till objektet i
newTime2 år, 1 månad och 7 dagar och skriv ut vilken veckodag det är. - skapa ett objekt av klassen TimeSpan och tilldela det resultatet av att
newTimesubtraheras frånpresentTime. Skriv ut resultatet.
... public static void PrintDateAndTime() { DateTime presentTime = DateTime.Now; Console.WriteLine("\nJust nu: " + presentTime.ToString());
Console.WriteLine("\nEnligt ISO 8601: " + presentTime.ToString("yyyy-MM-dd"));
Console.WriteLine("\nTiden: " + presentTime.ToString("HH:mm:ss"));
DateTime newTime = new DateTime(2010, 10, 23); Console.WriteLine("\nVeckodag 2010-10-23: " + newTime.DayOfWeek.ToString());
newTime = newTime.AddYears(2); newTime = newTime.AddMonths(1); newTime = newTime.AddDays(7); Console.WriteLine("\nVeckodag 2012-11-30: " + newTime.DayOfWeek.ToString());
TimeSpan diff = presentTime - newTime; Console.WriteLine("\nTimeSpan: " + diff.ToString()); }Anropa metoden som alternativ 4 i menyprogrammet.
Nu vill vi gärna ha veckodagarna på svenska. Då fixar vi genom att i klassen Helpers skapa en statisk array sweWeekdays med de svenska veckodagarna som strängar. I metoden PrintDateAndTime så tar vi reda på vilket nummer det är på veckodagen och använder det som index i den statiska array.
Här är koden.
namespace MenuApp2.src;
public class Helpers{ private static string[] sweWeekdays = new string[] { "måndag", "tisdag", "onsdag", "torsdag", "fredag", "lördag", "söndag" }; ... public static void PrintDateAndTime() { DateTime presentTime = DateTime.Now; Console.WriteLine("\nJust nu: " + presentTime.ToString());
Console.WriteLine("\nEnligt ISO 8601: " + presentTime.ToString("yyyy-MM-dd"));
Console.WriteLine("\nTiden: " + presentTime.ToString("HH:mm:ss"));
DateTime newTime = new DateTime(2010, 10, 23); int dayNo = (int)newTime.DayOfWeek; Console.WriteLine("\nVeckodag 2010-10-23: " + sweWeekdays[dayNo]);
newTime = newTime.AddYears(2); newTime = newTime.AddMonths(1); newTime = newTime.AddDays(7); dayNo = (int)newTime.DayOfWeek; Console.WriteLine("\nVeckodag 2012-11-30: " + sweWeekdays[dayNo].ToString());
TimeSpan diff = presentTime - newTime; Console.WriteLine("\nTimeSpan: " + diff.Days.ToString() + " dagar"); }Skriv ut alla veckodagar
Section titled “Skriv ut alla veckodagar”För att skriva ut veckodagarna så gör vi en ny metod i klassen Helpers som heter PrintDays().
Med Join
Section titled “Med Join”namespace MenuApp2.src;
public class Helpers{ ... public static void PrintDateAndTime() { ... TimeSpan diff = presentTime - newTime; Console.WriteLine("\nTimeSpan: " + diff.Days.ToString() + " dagar");
PrintDays(); }
private static void PrintDays() { Console.WriteLine(string.Join(", ", Helpers.sweWeekdays)); }}I metoden PrintDays() använder vi den inbyggda metoden Join för att göra en sträng av alla strängar i den statiska arrayen sweWeekDays(i koden tydliggörs att den tillhör klassen Heplers genom Helpers.sweWeekdays).
För att dela upp en sträng i delsträngar till en array av finns metoden Split.
Med array
Section titled “Med array”Eftersom veckodagarna är en array med strängar så kan vi skriva ut den istället. Vi uppdaterar PrintDays med en for-loop.
namespace MenuApp2.src;
public class Helpers{ ... public static void PrintDateAndTime() { ... PrintDays(); }
private static void PrintDays() { Console.WriteLine("\nVeckodagarna på svenska:"); foreach (string day in Helpers.sweWeekdays) { Console.WriteLine(day); } } ...Med lista
Section titled “Med lista”Men tänk om vi har en lista att skriva ut istället. Vi gör om veckodagarna till en lokal lista med strängar och tillför en ny metod PrintDays med en lista som inparameter. Nu använder vi foreach för att öva på den.
namespace MenuApp2.src;
public class Helpers{ ... public static void PrintDateAndTime() { ... PrintDays();
List<string> dayAsList = sweWeekdays.ToList(); PrintDays(dayAsList); }
private static void PrintDays(List<string> dayList) { Console.WriteLine("\nVeckodagarna på svenska:"); foreach (string day in dayList) { Console.WriteLine(day); } } ...När vi väljer menyalternativ 4 så ser det ut så här nu:
Sammanfattning
Section titled “Sammanfattning”Toppen, nu har vi:
- lärt oss att göra ett program med klasser utifrån klassdiagram
- tränat på iterationer
- tränat på metoder
- använt klassen DateTime för datum och tid i olika format
- skrivit ut listor
- använt en ASCII-bild