FÖRBÄTTRAT GRÄNSSNITT 1(6) BILAGA G till Programvaruprojekt FÖRBÄTTRAT GRÄNSSNITT multipc_logic_c Rev 2. Här visas ett gränssnitt som är bättre än det i bilaga F. Det innehåller däremot en del kvarvarande brister. En sämre variant av gränssnittet visas i bilaga F. Fetstil indikerar sådant som har modifierats jämfört med Rev 1, bilaga F. #ifndef MULTIPC_LOGIC_C_H #define MULTIPC_LOGIC_C_H ========================================================== Fil : multipc_logic_c.h Författare: Håkan Lindegren MultiPC Historik : 030215 Rev 1 030219 Rev 2 Förbättrat gränssnitt för get_first/get_next- funktioner utom get_first_/get_next_pupil ========================================================== #include "problem_s.h"; #include "details_answer_s.h"; #include "answered_problem_s.h"; #include "statistics_problem_s.h"; #include "problem_generator_c.h" #include "answers_log_c.h" #include "detailed_answers_log_c.h" #include "statistics_log_c.h" #include "multidb_c.h" Konstanter för felhantering vid läsning och skrivning av elevnamn ----------------------------------------------------- typedef enum { DB_OK, DB_CORRUPT, WRITE_FAILED, DB_FULL } db_status_t; class multipc_logic_c { public: Ska returnera en unik instans av multipc_logic_c Parametrar: INGA Retur: Pekare till unik instans Felhantering: INGEN ---------------------------------------------- static multipc_logic_c *get_instance();
FÖRBÄTTRAT GRÄNSSNITT 2(6) Returnerar status för elev DB För anrop INNAN get_first_pupil/get_next_pupil Parametrar: INGA Retur: Status hos elev DB: DB_OK eller DB_CORRUPT Felhantering: Via statusvärdet Om status är DB_CORRUPT kommer ny och tom elevfil att skapas. Anroparen kan sedan fortsätta. Jämför med detaljkraven under 120 ----------------------------------------------------- db_status_t get_db_status(); För att loopa över och läsa in elevnamn Parametrar: first_name: för lagring av elevs förnamn, minst 40 tecken last_name: för lagring av elevs efternamnnamn, minst 40 tecken item_found: sätts till 1 om elev fanns, 0 annars Retur: item_found = 1 indikerar att det fanns ytterligare en elev item_found = 0 ==> Ingen elev, övriga param oförändrade Felhantering: INGEN ---------------------------------------------- void get_first_pupil( void get_next_pupil( Sätter aktuell elev Parametrar: first_name: elevens förnamn, max 40 tecken last_name: elevens efternamn, max 40 tecken Retur: INGEN Felhantering: INGEN ---------------------------------------------- void set_pupil( char last_name[] ); Ger tillbaka namn på aktuell elev Parametrar: first_name: elevens förnamn, minst 40 tecken last_name: elevens efternamn, minst 40 tecken Retur: Namndata i first_name och last_name Felhantering: INGEN ---------------------------------------------- void get_pupil( char last_name[] );
FÖRBÄTTRAT GRÄNSSNITT 3(6) För lagring av nytt elevnamn Sätter också aktuell elev, d.v.s. anropar set_pupil Parametrar: first_name: elevens förnamn, max 40 tecken last_name: elevens efternamn, max 40 tecken db_status: sätts till DB_OK om det gick bra Retur: db_status = DB_OK ==> skrivning gick bra db_status = WRITE_FAILED ==> skrivning misslyckades, elev EJ lagrad db_status = DB_FULL ==> redan fullt i elev-db elev EJ lagrad Felhantering: Via db_status ---------------------------------------------------- void store_name( db_status_t &db_status ); För inställning av tabell Parametrar: table: heltal inom [1.. 10] Retur: INGEN Felhantering: INGEN ---------------------------------------------- void set_table( int table ); Returnerar inställd tabell Parametrar: INGA Retur: Vald tabell, ett heltal inom [1.. 10] Felhantering: INGEN ---------------------------------------------- int get_table(); Ska ge nästa framslumpade problem Parametrar: problem: operand_a/_b får värden Retur: operand_a inom [1.. 10], operand_b = aktuell tabell Felhantering: INGEN ---------------------------------------------- void get_next_problem( answered_problem_s &problem ); Rensar den interna svarsloggen För anrop innan ett prov startar Parametrar: INGA Retur: INGEN Felhantering: INGEN ---------------------------------------------- void clear_answers();
FÖRBÄTTRAT GRÄNSSNITT 4(6) För lagring av ett besvarat tal Parametrar: answer: svarsdata som ska lagras Retur: INGEN Felhantering: INGEN ---------------------------------------------- void store_answer( answered_problem_s &answer ); För att loopa över de givna svaren i ett prov Parametrar: answer: får svarsdata för ett svar correct_answer: får korrekt svar [1.. 100] item_found: sätts till 1 om svar fanns, 0 annars Retur: item_found = 1 indikerar att det fanns ytterligare ett svar item_found = 0 ==> Inget svar, övriga param oförändrade Felhantering: INGEN ---------------------------------------------- void get_first_answer( answered_problem_s &answer, int &correct_answer, void get_next_answer( answered_problem_s &answer, int &correct_answer, För att loopa över statistiken i vald tabell Parametrar: answer_statistics: får statistik om ett tal item_found: sätts till 1 om svar fanns, 0 annars Retur: item_found = 1 indikerar att det fanns ytterligare statistik item_found = 0 ==> Ingen statistik, övriga param oförändrade Felhantering: INGEN ---------------------------------------------- void get_first_stats( statistics_problem_s &answer_statistics, void get_next_stats( statistics_problem_s &answer_statistics, För att ställa in aktuellt tal för detaljstatistiken Ska kombineras med set_table() Parametrar: operand_a: värdet av första operanden Retur: INGEN Felhantering: INGEN ---------------------------------------------- void set_details_number( int number ); Returnerar inställt details_number
FÖRBÄTTRAT GRÄNSSNITT 5(6) Parametrar: INGA Retur: Inställd detaljoperand, ett heltal inom [1.. 10] Felhantering: INGEN ---------------------------------------------- int get_details_number(); För att loopa över detaljstatistik för vald tabell och valt detaljnummer Parametrar: answer_details: data får svar som avgivits correct_answer: får korrekt svar item_found: sätts till 1 om svar fanns, annars 0 Retur: item_found = 1 indikerar att det fanns ytterligare svar item_found = 0 ==> Inget svar, övriga param oförändrade Felhantering: INGEN ---------------------------------------------- void get_first_detail( int &answer, void get_next_detail( int &answer, private: Privat konstruktor, allt enligt Singleton multipc_logic_c(); Den unika instansen. Instansieras av get_instance(), allt enligt Singleton multipc_logic_c *unique_instance; }; Instansvariabler. Instansieras av konstruktorn. problem_generator_c *problem_generator; answers_log_c *answers_log; detailed_answers_log_c *detailed_answers_log; statistics_log_c *statistics_log; multidb_c *multidb; #endif MULTIPC_LOGIC_C_H Kommentar Då är problemen med att gränssnittet öppnas för felaktiga anrop delvis åtgärdade. Funktionerna för att hantera elevnamn innehåller dock fortfarande samma brist. Så här ser det t.ex. ut för de funktioner som ska ge tillbaka elevdata: För att loopa över och läsa in elevnamn Parametrar: first_name: för lagring av elevs förnamn, minst 40 tecken last_name: för lagring av elevs efternamnnamn, minst 40 tecken item_found: sätts till 1 om elev fanns, 0 annars Retur: item_found = 1 indikerar att det fanns ytterligare en elev item_found = 0 ==> Ingen elev, övriga param oförändrade
FÖRBÄTTRAT GRÄNSSNITT 6(6) Felhantering: INGEN ---------------------------------------------- void get_first_pupil( void get_next_pupil( Gränssnittet kräver att den som anropar gör det på rätt sätt. En klass, eller en struct, för att hantera kombinationen av för- och efternamn bör införas. Då kan funktionerna i rutan förbättras och risken för felaktiga anrop minskas. Orsaken till att jag låter brister vara kvar, trots förbättringen, är att det ofta ser ut så i praktiken. I processen att förbättra krav, design eller testfall kommer man hela tiden på nya saker som kan förbättras. Någon gång måste man säga stopp, det här räcker. Jag har däremot aldrig varit med om att någon har sagt: Om vi ändå hade börjat programmera tidigare. i efterhand. Fortfarande endast lite felhantering. Borde inte det åtgärdas? Kanske, kanske inte. Kravställningen för GUI:t är sådan att där ska det läggas begränsningar på vad användaren kan mata in. Risken att det t.ex. kommer in tabellval utanför [1.. 10] är därmed relativt liten. Det gör att det troligen är acceptabelt att multipc_logic_c förväntar sig korrekta indata. Om det däremot vore så att vi inte visste något om den kod som ska anropa multipc_logic_c borde vi reda ut var felhanteringen egentligen ska ligga. Tröskeln för att anropa multipc_logic_c har ökat mellan Rev 1 (bilaga F) och Rev 2. Här, med Rev 2, måste den som ska anropa funktioner sätta sig in även i de här gränssnitten: problem_s En struct som ska hålla reda på två stycken heltal. Heltalen ska representera ett multiplikationsproblem, t.ex. 7*3. answered_problem_s En struct som är en problem_s med ett heltal för avgivet svar och ett heltal för den tid det tog att avge svaret. details_answer_s Struct som ska hålla detaljer om ett enda problem för detaljstatistiken. I praktiken en problem_s och en vektor med alla elevens svar, dock högst 30 stycken. Att det ska vara högst 30 stycken ges av detaljkraven för MultiPC. statistics_problem_s En struct som är en problem_s förstärkt med två heltal för antalet försök och antalet rätt. Vi har alltså fått ett säkrare gränssnitt, men vi har gjort det besvärligare att anropa det. Är det värt besväret? Jo, det är det troligen. Tröskeln har visserligen blivit högre, men inte mycket högre. Den tid vi förlorar på att anroparen tvingas lära sig att anropa på rätt sätt vinner vi tillbaka i samband med test-och-felrättning eftersom anropen troligen görs på rätt sätt.