The singleton pattern that is introduced to the project is applied to a class being used to maintain the inventory's collection of books. The singleton will prevent access from multiple threads being handled incorrectly, and, another pattern, the repository pattern, will be used to create a facade over the data that is being managed.
The repository pattern provides an abstraction over a repository to provide a layer between the business logic of an application and the underlying data. This provides several advantages. By having a clean separation, our business logic can be maintained and unit tested independently of the underlying data. Often, the same repository pattern class can be reused by multiple business objects. An example of this could be GetInventoryCommand, AddInventoryCommand, and UpdateInventoryCommand objects; all of these objects use the same repository class. This allows us to test the logic in these commands in isolation from the repository. Another advantage of the pattern is that it enables centralized data-related policies to be more easily implemented, such as caching.
To begin, let's consider the following interface that describes the methods that the repository will implement; it contains a method for retrieving the books, adding a book, and updating the quantity of the book:
internal interface IInventoryContext
{
Book[] GetBooks();
bool AddBook(string name);
bool UpdateQuantity(string name, int quantity);
}
The initial version of the repository is as follows:
internal class InventoryContext : IInventoryContext
{
public InventoryContext()
{
_books = new Dictionary<string, Book>();
}
private readonly IDictionary<string, Book> _books;
public Book[] GetBooks()
{
return _books.Values.ToArray();
}
public bool AddBook(string name)
{
_books.Add(name, new Book { Name = name });
return true;
}
public bool UpdateQuantity(string name, int quantity)
{
_books[name].Quantity += quantity;
return true;
}
}