ChatGPT 4 SUPERTENTA(old) Flashcards
Generiska Typer
2p. Förklara syftet med generiska typer och varför de kan vara fördelaktiga att använda. Ge ett exempel på hur man kan använda en generisk typ.
Generiska typer möjliggör att man kan skapa datastrukturer som kan hantera data av vilken typ som helst, utan att förlora typinformation. De kan vara fördelaktiga att använda eftersom de tillåter återanvändning av kod och bevarar typsäkerhet. Exempel: En lista av generisk typ kan användas för att lagra element av vilken datatyp som helst, t.ex. List<int>, List<String> osv.</String></int>
Generiska Kollektioner
2p. Beskriv hur generiska kollektioner skiljer sig från icke-generiska. Varför skulle man välja att använda en generisk kollektion?
Generiska kollektioner är typsäkra och låter programmeraren specificera vilken typ av data som kan lagras i dem. Icke-generiska kollektioner kan hålla data av vilken som helst typ, vilket kan leda till körtidsfel. Användning av generiska kollektioner kan förbättra prestanda, minska risken för fel och ge bättre kodläsbarhet.
Komposition och Injektion
2p. a. Vad menas med komposition i samband med objektorienterad programmering? Hur kan detta vara fördelaktigt jämfört med arv?
Komposition innebär att ett objekt skapas genom att sammanställa andra objekt snarare än att ärva deras egenskaper. Detta kan vara fördelaktigt eftersom det leder till mer flexibel och dekopplad kod, vilket gör det enklare att ändra, underhålla och återanvända koden jämfört med arv.
Komposition och injektion
2p. b. Vad innebär dependency injection? Ge ett exempel där det är fördelaktigt att använda dependency injection.
Dependency injection innebär att ett objekts beroenden (ofta i form av tjänster eller andra objekt) tillhandahålls (injiceras) av ett externt system snarare än att objektet skapar sina egna beroenden. Detta kan vara fördelaktigt för att minska hård koppling mellan komponenter, vilket gör systemet mer modulärt och lättare att testa. Exempel: Istället för att en databascontroller skapar sin egen databasanslutning kan den få en anslutning injicerad, vilket gör det enklare att byta till en mock-databas under testning.
Lambda-uttryck
2p. Vad är ett lambda-uttryck och hur kan det användas? Ge ett exempel där lambda-uttrycket förenklar koden.
Ett lambda-uttryck är en kort, in-line funktion som ofta används för att skicka funktionalitet som argument till högre ordningens funktioner. De kan användas för att skapa kompakta representationer av funktioner utan att namnge dem. Exempel: Att filtrera en lista med heltal för att endast behålla de jämna talen kan göras med ett lambda-uttryck såsom list.filter(x => x % 2 == 0).
Observer Pattern
2p. Hur kan Observer pattern hjälpa till att skapa en mer dekopplad kod? Ge ett exempel på en situation där detta mönster skulle vara lämpligt.
Observer pattern möjliggör en en-till-många beroendeförhållande där ett objekt (subjektet) notifierar sina observatörer om någon förändring. Detta leder till dekopplad kod eftersom subjektet inte behöver veta något om sina observatörer. Exempel: Ett nyhetsbrevsystem där prenumeranter (observatörer) blir meddelade när ett nytt inlägg (subjekt) publiceras.
Events och Delegater
2p. Hur skiljer sig events från delegater? Ge ett exempel där det är mer fördelaktigt att använda en event än en delegat.
Delegater är objekt som refererar till metoder, medan events är en mekanism som gör att ett objekt kan meddela andra objekt om att något har hänt. Medan delegater kan peka på vilken metod som helst, försäkrar events att endast de specifika händelserna som objektet publicerar kan anropas. Ett exempel kan vara ett GUI-system där en knapp (objektet) utlöser ett “click”-event. Istället för att direkt anropa en metod (delegat) skickar det ett event som andra delar av systemet kan prenumerera på.
LINQ
2p. Vad står LINQ för och hur kan det användas för att bearbeta kollektioner av data? Ge ett exempel på en LINQ-fråga.
LINQ står för “Language Integrated Query” och är en teknik som låter programmerare skriva kraftfulla och läsbart queries direkt i programmeringsspråket. Det kan användas för att bearbeta kollektioner av data på ett deklarativt sätt. Exempel: Att hämta alla boktitlar från en lista med böcker som är skrivna av en viss författare kan se ut som var booksByAuthor = books.Where(book => book.Author == “Desired Author”).Select(book => book.Title).
Varians i Praktiken
2p. Ge ett exempel som demonstrerar konceptet av kovarians med generiska typer. Förklara varför detta är tillåtet eller inte tillåtet.
Kovarians med generiska typer tillåter att en generisk typ som använder en superklass kan ersättas av en generisk typ som använder en subklass. För att illustrera detta, låt oss tänka oss två klasser: Animal och Cat där Cat är en subklass till Animal. Om vi har en generisk klass eller gränssnitt, t.ex. Container<T>, och Container<Animal> är kovariant, skulle det vara möjligt att använda en Container<Cat> där en Container<Animal> förväntas. Men det är viktigt att notera att kovarians inte alltid är säkert för alla operationer. Till exempel, om Container tillåter insättning av objekt av typ T, skulle kovarians inte vara säkert eftersom vi riskerar att försöka lägga in en hund i en Container<Cat>. Därför måste språk som stöder kovarians med generiska typer begränsa vilka operationer som är tillåtna på kovarianta generiska typer.</Cat></Animal></Cat></Animal></T>
Designmönster och Underhållbarhet
2p. Diskutera hur antingen komposition, observer pattern eller dependency injection kan påverka underhållbarheten baserat på två (och endast två) av de fem punkter vi har behandlat under kursen: Modularitet, Återanvändbarhet, Analysbarhet, Modifierbarhet, Testbarhet.
Observer pattern kan öka modularitet eftersom den dekopplar subjektet från dess observatörer. Detta betyder att ändringar i ett subjekt eller dess observatörer inte nödvändigtvis påverkar varandra. Detta gör att varje modul kan utvecklas, testas och förbättras oberoende. Samtidigt förbättras testbarheten genom att det blir enklare att mocka observatörer vid testning av subjektet, eftersom de två är dekopplade.
Iterator Pattern
2p. Vad är Iterator pattern och hur hjälper det i att bearbeta kollektioner av data? Ge ett praktiskt exempel på hur detta mönster kan användas.
Iterator pattern tillhandahåller ett sätt att få åtkomst till elementen i en kollektion av objekt sekventiellt utan att exponera den underliggande representationen. En iterator definierar ett gränssnitt med metoder för att gå igenom och även kontrollera slutet av kollektionen. Exempel: Tänk dig en bokhylla med böcker. Istället för att direkt interagera med varje bok i hyllan, skulle en iterator ge dig en bok i taget från början till slut. Denna abstraktion låter dig ändra hur bokhyllan är organiserad utan att påverka hur du bläddrar genom böckerna.
Generics vs. Subtyping
2p. Beskriv skillnaden mellan generisk typning (som med generiska typer) och subtypning. Varför kan man ibland föredra den ena över den andra?
Generisk typning (parametrisk polymorfism) tillåter att koden skrivs på ett flexibelt sätt som inte är beroende av en specifik datatyp, medan subtypning (subtypspolymorfism) tillåter att en objekttyp behandlas som en av sina superklasser. Generisk typning är ofta fördelaktig för återanvändbar kod, medan subtypning används för att skapa en hierarki av relaterade klasser där subklasser kan användas i stället för sina superklasser. Valet mellan de två beror på det specifika problemet som ska lösas: för återanvändbarhet över många olika typer kan generiska typer vara föredragna, medan för system som kräver en väldefinierad klasshierarki kan subtypning vara mer lämplig.
Varians i Teorin
2p. Vad menas med varians när det kommer till generiska typer? Hur påverkar det användningen av generiska typer?
Varians inom kontexten av generiska typer avser hur subtyprelationer mellan sammansatta typer (till exempel listor eller andra generiska behållare) relaterar till subtyprelationer mellan deras komponenter. Det finns tre huvudtyper av varians:
Kovarians: Om typ A är en subtyp av B, så kan en container av A (t.ex. List<a>) ses som en subtyp av en container av B (List<b>). Detta tillåter flexibilitet vid läsning från generiska strukturer.</b></a>
Kontravarians: Om typ A är en subtyp av B, kan en container av B ses som en subtyp av en container av A när det gäller att sätta in eller skicka data.
Invarians: Här finns ingen relation mellan containerdatatyper baserat på deras innehållstyper, vilket innebär att de inte automatiskt kan konverteras baserat på deras innehålls relation.
Varians påverkar användningen av generiska typer genom att erbjuda en balans mellan typsäkerhet och flexibilitet. Korrekt användning av varians säkerställer att programmet fungerar som förväntat samtidigt som det ger flexibiliteten att använda subtyper där det är lämpligt.