Екатерина обнови решението на 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
?
Добър въпрос...