P-uppgift: Prototyp

Programmeringsteknik

Hoppa till: navigering, sök
       Information          Kodskelett          Prototyp          Granskning          Redovisning          Bibliotek      

Innehåll:

  • Prototyp
  • Prototyp till Fiktiv P-uppgift: Bibliotek
  • Inlämningsuppgift: prototyp

En prototyp är en första körbar version av programmet som innehåller den mest grundläggande funktionaliteten. I det här skedet behöver programmet ännu inte har fullt utbyggd felhantering, eventuella extrauppgifter behöver inte vara implementerade och vissa delar av programmet kan innehålla funktioner som ännu inte utför sin uppgift. Syftet med att lämna in en prototyp är att vi ska kunna ge tips och råd om förbättringar och ändringar redan innan programmet är helt klart.

Prototyp till bibliotek

Se Bibliotek för uppgiftslydelse samt Kodskelett för kodskelett.

Prototypen behöver inte implementera all funktionalitet. I biblioteksexemplet har vi valt att starta med inläsning och utskrift till fil. Vi har också lagt till de två första funktionerna i menyn: att söka på titel och att söka på författare.

När man jobbar med att skriva kod så upptäcker man ofta att den ursprungliga kodskelettet måste modifieras. Studera koden i exemplet nedan noggrant och lägg märke till ändringarna.


# Titel: Bibliotek (prototyp)
# Författare: Stefan Nilsson
# Datum: 2007-06-29
#
# Det här är ett program för hantering av enklare biblioteksrutiner.
#
# Programmet lagrar böckerna i en fil med namnet "bibliotek.txt"
# mellan körningarna. Varje rad innehåller en bok beskriven på
# följande format:
#
#    <AUTHOR>/<TITLE>
#
# eller
#
#    <AUTHOR>/<TITLE>/Utlånad
#
# om boken är utlånad. Exempel på datafil:
#
#    Bälter/Programmeringsteknik med Python/Utlånad
#    Bälter/Pythonvetaren


# --------  En klass som beskriver en bok.  --------
# Attribut:
#    author - namnet på författaren
#    title - bokens titel
#    isBorrowed - en variabel som är True om boken är utlånad.
#
class Book:
    # Skapar en ny bok.
    def __init__(self, author, title):
        self.author = author
        self.title = title
        self.isBorrowed = False

    # Returnerar en sträng som beskriver boken.
    # Format: <author>: <title> (utlånad)
    def __str__(self):
        author_and_title = self.author + ": " + self.title
        if self.isBorrowed:
            return author_and_title + " (utlånad)"
        else:
            return author_and_title


# --------  En klass som beskriver en bibliotekskatalog.  --------
# Attribut:
#    books - en lista som innehåller samtliga böcker.
#
class Catalog:
    # Skapar en bibliotekskatalog med de böcker som finns i filen.
    def __init__(self, filename):
        self.books = list()
        file = open(filename, "r")
        for line in file:
            parts = line.strip().split("/")
            if (len(parts) >= 2):
                book = Book(parts[0], parts[1])
                if len(parts) == 3:
                    book.isBorrowed = True
                self.books.append(book)
        file.close()

    # Sparar hela bibliotekskatalogen i en fil.
    def save(self, filename):
        file = open(filename, "w")
        for book in self.books:
            file.write(book.author + "/" + book.title)
            if book.isBorrowed:
                file.write("/Utlånad")
            file.write("\n")
        file.close()

    # Returnerar boken om den finns, annars None.
    # Skiljer inte på små och stora bokstäver.
    def find_title(self, title):
        for book in self.books:
            if are_equal(title, book.title):
                return book
        return None

    # Returnerar en lista på böcker av en viss författare.
    # Return en tom lista om det inte finns några böcker.
    # Skiljer inte på stora och små bokstäver.
    def find_author(self, author):
        book_list = list()
        for book in self.books:
            if are_equal(author, book.author):
                book_list.append(book)
        return book_list


# --------  Hjälpfunktioner  --------
    
# Returnerar True om s1 och s2 är lika.
# Skiljer inte på små och stora bokstäver och tar bort
# eventuella blanktecken i början och slutet av strängen.
def are_equal(s1, s2):
    return s1.strip().upper() == s2.strip().upper()


# --------  Funktioner för textgränssnitt  --------

INDENT = "  " # Tomma tecken i början av indragna rader

# Skriver ut valmenyn.
def print_menu():
    print(INDENT + "T  söka på Titel.")
    print(INDENT + "F  söka på Författare.")
    print(INDENT + "L  Låna bok.")
    print(INDENT + "Å  Återlämna bok.")
    print(INDENT + "N  lägga in Ny bok.")
    print(INDENT + "B  ta Bort bok.")
    print(INDENT + "A  lista Alla böcker.")
    print(INDENT + "S  Sluta.")

# Läser in och returnerar första bokstaven i användarens val.
# Omvandlar liten bokstav till stor.
def choose():
    choice = input("Vad vill du göra? ")
    return choice[0].upper()

# Söker på titel.
def search_title(catalog):
    title = input("Vilken titel vill du söka efter? ")
    book = catalog.find_title(title)
    if (book == None):
        print(INDENT + "Hittade ingen bok med den titeln.")
    else:
        print(INDENT + book)

# Söker på författare.
def search_author(catalog):
    author = input("Vilken författare vill du söka efter? ")
    book_list = catalog.find_author(author)
    if len(book_list) == 0:
        print(INDENT + "Hittade inga böcker av den författaren.")
    else:
        print(INDENT + "Hittade " + str(len(book_list)) + " böcker")
        for book in book_list:
            print(INDENT + book)

# Lånar en bok.
def borrow_book(catalog):
    return

# Återlämnar en bok.
def return_book(catalog):
    return

# Lägger till en ny bok.
def add_book(catalog):
    return

# Tar bort en bok.
def delete_book(catalog):
    return


# --------  Huvudprogram  --------
def main()
    print("Välkommen till biblioteksprogrammet!")

    FILENAME = "bibliotek.txt"
    catalog = Catalog(FILENAME)

    # Testutskrift
    print("Antal böcker:" + str(len(catalog.books)))
    for book in catalog.books:
        print book

    print_menu()

    choice = choose();
    while choice != "S":
        if choice == "T":
            search_title(catalog)
        elif choice == "F":
            search_author(catalog)
        choice = choose()

    catalog.save(FILENAME)

    print(INDENT + "Välkommen åter!")

main()
  • Klassen Bibliotek har bytt namn till Catalog, ett namn som beskriver klassen bättre. Ett objekt av den här klassen representerar ju inte ett helt bibliotek utan bara en bibliotekskatalog.
  • Många av metoderna i Catalog-klassen har ändrats. När vi började skriva koden så märkte vi att många av de ursprungliga metoderna i klassen Bibliotek gjorde två helt skilda saker: de gjorde både operationer på bibliotekskatalogen samtidigt som de skötte det textbaserade användargränssnittet. En bättre lösning är att metoderna i klassen Catalog endast hanterar operationerna på bibliotekskatalogen. Användargränsnittet har vi implementerat separat med hjälp av ett antal funktioner.
  • Vi har nu bestämt hur data ska lagras på fil och varit noga med att dokumentera detta i programmet. Denna viktiga information saknades helt i kodskelettet.
  • Lägg märke till att det finns en extra utskrift (som inte ska vara med i det färdiga programmet) i huvudprogrammet. Just efter att vi har läst in data från filen och skapat en ny Catalog så skriver vi ut innehållet i listan books. Den här typen av testutskrifter är mycket användbara för att kolla att programmet fungerar som man har tänkt sig och för att leta efter eventuella fel.
  • När vi skrev koden så upptäckte vi ibland att vi upprepade samma kod på flera ställen. Det brukar vara en tydlig indikation på att det är lämpligt att introducera en ny funktion. Ett exempel är hjälpfunktionen are_equal som kollar om två strängar är lika så när som på små och stora bokstäver samt överflödiga blanktecken i början och slutet av strängarna. Den här funktionen la vi till eftersom samma kod dök upp i de båda funktionerna search_title och search_author.
  • Når vi skrev programmet så upptäckte vi att det fanns ett stort antal utskrifter som alla började med blanktecken: print ' text...'. För att slippa skriva om samma sak, en form av onödig hårdkodning, och för att lättare kunna ändra programmet i framtiden så införde vi istället konstanten INDENT = ' '.
  • Eftersom vi har planer på att göra extrauppgiften för betyg A, att lägga till ett grafiskt användargränssnitt, så har vi försökt att skilja ut den kod som hanterar kommunikationen till användaren från den kod som hanterar logiken i programmet. På det sättet blir det mycket enklare när vi ska byta ut textgränssnittet mot ett grafiskt gränssnitt. Målet är inte bara att få programmet att fungera, utan också att utforma det på ett sådant sätt att det är lätt att förstå och modifiera i framtiden.


Inlämningsuppgift: prototyp

Skriv en prototyp till din P-uppgift och lämna in den på vanligt sätt under rubriken "P-uppgift Prototyp", döp filen till Förnamn_efternamn_prototyp.py

KONTROLL INNAN INLÄMNING:
* Innehåller ditt program bara den mest grundläggande funktionaliteten?
* Har du tagit till dig av eventuell feedback som du fick för kodskelettet?
* Har du testat ditt program så att det är körbart?
* Har du namngivit dina variabler och funktioner väl?
* Ser din körning ut som exemplen?
* Använder du dig av inparametrar och returvärden?
* Har du kommenterat din kod?
* Har du undvikit kodupprepning?