Екатерина обнови решението на 03.12.2015 23:57 (преди над 2 години)
+package main
+
+import (
+        "encoding/json"
+        "encoding/xml"
+        "fmt"
+        "sync"
+)
+
+const MaxRegistered = 4
+
+type Library interface {
+        AddBookJSON(data []byte) (int, error)
+        AddBookXML(data []byte) (int, error)
+        Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
+}
+
+type LibraryRequest interface {
+        GetType() int
+        GetISBN() string
+}
+
+type LibraryResponse interface {
+        GetBook() (fmt.Stringer, error)
+        GetAvailability() (available int, registered int)
+}
+
+type MyLibrary struct {
+        books      map[string]*Book
+        librarians chan struct{}
+        mu         *sync.Mutex
+}
+
+type MyLibraryResponse struct {
+        book *Book
+        err  error
+}
+
+type Book struct {
+        Isbn       string  `json:"isbn" xml:"isbn,attr"`
+        Title      string  `json:"title" xml:"title"`
+        Author     *Author `json:"author" xml:"author"`
+        Ratings    []int   `json:"ratings" xml:"ratings"`
+        available  int
+        registered int
+        mu         *sync.Mutex
+}
+
+type Author struct {
+        FirstName string `json:"first_name" xml:"first_name"`
+        LastName  string `json:"last_name" xml:"last_name"`
+}
+
+func (b *Book) String() string {
+        author := b.Author.FirstName + " " + b.Author.LastName
+        return "[" + b.Isbn + "] " + b.Title + " от " + author
+}
+
+func (b *Book) getRegistered() int {
+        b.mu.Lock()
+        defer b.mu.Unlock()
+        return b.registered
+}
+
+func (b *Book) incrementRegistered() {
+        b.mu.Lock()
+        defer b.mu.Unlock()
+        b.registered++
+}
+
+func (b *Book) getAvailable() int {
+        b.mu.Lock()
+        defer b.mu.Unlock()
+        return b.available
+}
+
+func (b *Book) incrementAvailable() {
+        b.mu.Lock()
+        defer b.mu.Unlock()
+        b.available++
+}
+
+func (b *Book) decrementAvailable() {
+        b.mu.Lock()
+        defer b.mu.Unlock()
+        b.available--
+}
+
+func (resp *MyLibraryResponse) GetBook() (fmt.Stringer, error) {
+        return resp.book, resp.err
+}
+
+func (resp *MyLibraryResponse) GetAvailability() (int, int) {
+        if resp.book == nil {
+                return 0, 0
+        }
+        return resp.book.getAvailable(), resp.book.getRegistered()
+}
+
+func (lib *MyLibrary) getBook(isbn string) (*Book, bool) {
+        lib.mu.Lock()
+        defer lib.mu.Unlock()
+        b, ok := lib.books[isbn]
+        return b, ok
+}
+
+func (lib *MyLibrary) addBook(newBook Book) (int, error) {
+        isbn := newBook.Isbn
+        if b, ok := lib.getBook(isbn); ok {
+                if b.getRegistered() >= MaxRegistered {
+                        err := fmt.Errorf("Има %d копия на книга %s", b.getRegistered(), isbn)
+                        return b.getRegistered(), err
+                }
+        } else {
+                lib.mu.Lock()
+                lib.books[isbn] = &newBook
+                lib.mu.Unlock()
+        }
+        lib.books[isbn].incrementAvailable()
+        lib.books[isbn].incrementRegistered()
+        return lib.books[isbn].getRegistered(), nil
+}
+
+func (lib MyLibrary) AddBookJSON(data []byte) (int, error) {
+        newBook := Book{mu: &sync.Mutex{}}
+        json.Unmarshal(data, &newBook)
+        return lib.addBook(newBook)
+}
+
+func (lib MyLibrary) AddBookXML(data []byte) (int, error) {
+        newBook := Book{mu: &sync.Mutex{}}
+        xml.Unmarshal(data, &newBook)
+        return lib.addBook(newBook)
+}
+
+func (lib MyLibrary) occupyLibrarian(reqs chan LibraryRequest, resps chan LibraryResponse) {
+        for req := range reqs {
+                var err error
+                isbn := req.GetISBN()
+
+                book, ok := lib.getBook(isbn)
+                if ok {
+                        switch req.GetType() {
+                        case 1:
+                                if book.getAvailable() == 0 {
+                                        err = fmt.Errorf("Няма наличност на книга %s", isbn)
+                                } else {
+                                        book.decrementAvailable()
+                                }
+                        case 2:
+                                if book.getAvailable() >= book.getRegistered() {
+                                        err = fmt.Errorf("Всички копия са налични %s", isbn)
+                                } else {
+                                        book.incrementAvailable()
+                                }
+                        }
+                } else {
+                        err = fmt.Errorf("Непозната книга %s", isbn)
+                }
+                resps <- &MyLibraryResponse{book, err}
+        }
+        close(resps)
+        <-lib.librarians
+}
+
+func (lib MyLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+        requests := make(chan LibraryRequest)
+        responses := make(chan LibraryResponse)
+        lib.librarians <- struct{}{}
+        go lib.occupyLibrarian(requests, responses)
+        return requests, responses
+}
+
+func NewLibrary(librarians int) Library {
+        return MyLibrary{
+                books:      make(map[string]*Book),
+                librarians: make(chan struct{}, librarians),
+                mu:         &sync.Mutex{},
+        }
+}
so far 
.
Само се чудя, има ли идея да имплементираш Library с MyLibrary, а не *MyLibrary?
Добър въпрос...
