I am doing a beginner C++ project and it's simply a library management system where a student will hire, give back a book, book and hire records are stored in a binary file etc.
I'm approaching the project as though the project would be used by other developers and that I need to design the classes so they cannot be incorrectly used, the project can be scaled/extended at a later date easily and avoid gotchas/bugs down the track so I am being very strict (overkill almost) with my implementation.
Therefore, I have some features of the LibraryBook
and LibraryManagementSystem
classes that I want to implement but don't quite know if this is the best way of doing it.
Classes:
LibraryManagementSystem
(LMS)LibraryBook
Student
LibraryBook
features I want to implement:
- The class has the expected private properties of title, author, availability, id. I have made the LMS a friend class so that it and only it can change the books availability, maybe even author, title (for scalability/extendability). Would you use
friend
here or maybe another technique? - A book object should only ever be created by the LMS, this makes sense I guess because a Student shouldn't be able to make a new book only the LMS. So I was thinking of making the
LibraryBook
class private but that means aStudent
won't even be able to hold a book (as a property in their class). I am thinking I should only ever give a handle of the book to theStudent
? Maybe this is the case for the application of the factory design pattern. - A
LibraryBook
must always have its title, author, etc. defined, so I have made the constructor explicit. Should I make the default constructor private? That way a book can only ever be created with defined title, author, etc.
LMS features I want to implement:
- I want to store the
LibraryBooks
in astd::map <string, std::shared_ptr<LibraryBook>>
. This is because a student will most likely ask/search for the book by title (title string = key), theLibraryBook
dynamic memory will be automatically deleted and I can give the Student aweak_ptr
to theLibraryBook
which means they can't change anything on that object.
Knowing what I want to achieve above; can you provide advice on design patterns and etc. Have I made any errors in my implementation below?
class Student
{
public:
// I dont think that hire book should be a student method but a LMS method because the LMS issues a book, creates a record etc.
weak_ptr<LibraryBook> curBook; // is this ok as public? or should only the LMS be able to set a students book? Maybe this property only should be friend with LMS?
protected:
private:
const string firstName;
const string lastName;
const unsigned int ID;
};
class LibraryBook
{
public:
friend class LibraryManagementSystem;
protected:
private:
explicit LibraryBook(string nTitle, string nAuthor) : title(nTitle), author(nAuthor) { } // will this mean noone not even LMS can create a book using the default // No need to implement destructor because implicitly created and theres no dyn memory in this class
LibraryBook(const LibraryBook& lB); // dont implement to disallow copying a book
LibraryBook& operator=(const LibraryBook& lB); // dont implement to disallow copying a book
const string title;
const string author;
const unsigned int ID;
};
class LibraryManagementSystem
{
public:
static LibraryManagementSystem& Instance()
{
static LibraryManagementSystem instance;
return instance;
}
weak_ptr<LibraryBook> hireBook(string bookTitle, Student& student)
{
weak_ptr<LibraryBook> book; // initialised as null ptr I think?
if (libraryBooks.find(bookTitle) == libraryBooks.end())
// what should I return? An empty/null weak_ptr?
book = libraryBooks[bookTitle]; // is this cast allowed/possible? Is it allowed to write/overwrite a weak ptr?
student.curBook = book;
// TODO: create LMS record of who has book, when due back, etc.
return book;
}
protected:
private:
LibraryManagementSystem() {}
~LibraryManagementSystem() {}
LibraryManagementSystem(const LibraryManagementSystem& lms); // dont implement to disallow copy constructor
LibraryManagementSystem& operator=(const LibraryManagementSystem& lms); // dont implement assignment operator
map<string, shared_ptr<LibraryBook>> libraryBooks;
};
LibraryBook
a value type (e.g. storing the books in astd::set<LibraryBook>
and handing out books by value)? (2) Do you care about thread-safety and multithreading? (3) What is the purpose ofStudent
in this system? Can anyone besidesStudent
s check out a book? Can a singleStudent
check out multiple books at once? Can books be returned to the library? \$\endgroup\$