I am trying to come up with a good File System Design using C++ / OOP. This is being done to gain an understanding of System Design and Design Patterns.
I have some basic functionality, like reading and writing files, adding and deleting files and folders, calculating the size of files and folders. The design pattern I am trying to use is Composite Design pattern.
My design uses a base class called BaseComponent
which contains facilities common to both files and folders. The class Folder
deals with adding and deleting of files and folders while class File
deals with reading and writing of files. Both File
and Folder
are derived from BaseComponent
.
Here is the code:
#include <iostream> #include <string> #include <set> class BaseComponent { std::string name_v; BaseComponent* parent_v; bool is_folder; public: BaseComponent(std::string name, BaseComponent* parent = nullptr, bool f = true) : name_v{name}, parent_v{parent}, is_folder{f} { } virtual ~BaseComponent() { } void change_name(std::string& name) { name_v = name; } std::string name() const { return name_v; } BaseComponent* parent() const { return parent_v; } void del() { if(parent_v == nullptr) { return; } parent_v -> delete_component(this); } virtual int size() const { return 0; } virtual void add_component(BaseComponent*) { } virtual void delete_component(BaseComponent*) { } }; class Folder : public BaseComponent { std::set<BaseComponent*> children; public: Folder(std::string name, Folder* parent = nullptr, bool is_folder = true) : BaseComponent{name, parent, is_folder} { } ~Folder() { } int size() const { int size_v = 0; for(auto child : children) { size_v += child -> size(); } return size_v; } int num_ff() { return children.size(); } void add_component(BaseComponent* b) { children.insert(b); } void delete_component(BaseComponent* b) { children.erase(b); } }; class File : public BaseComponent { std::string contents_v; public: File(std::string contents, std::string name, Folder* parent, bool is_folder = false) : BaseComponent{name, parent, is_folder}, contents_v{contents} { } ~File() { } int size() const { return sizeof(this); } void write(std::string content) { contents_v = content; } std::string read() const { return contents_v; } }; /*class FileSystem { };*/ int main() { Folder root{"/"}; Folder home{"home", &root}; root.add_component(&home); Folder lib{"lib", &root}; root.add_component(&lib); Folder dev{"dev", &root}; root.add_component(&dev); std::cout << "No. of components in root: " << root.num_ff() << "\n"; std::cout << "No. of components in home: " << home.num_ff() << "\n"; File test{"x = 0, y = 0", "Configuration.txt", &root}; root.add_component(&test); Folder ws{"ws", &home}; home.add_component(&ws); File fs{"fs file", "fs.cpp", &ws}; ws.add_component(&fs); File git{"user: dummy", "git_config", &home}; home.add_component(&git); std::cout << "Contents of git: " << git.read() << "\n"; git.write("user: new\n email:[email protected]"); std::cout << "Contents of git: " << git.read() << "\n"; std::cout << "No. of components in root: " << root.num_ff() << "\n"; std::cout << "No. of components in home: " << home.num_ff() << "\n"; std::cout << "No. of components in ws: " << ws.num_ff() << "\n"; dev.del(); std::cout << "No. of components in root: " << root.num_ff() << "\n"; std::cout << "Size of git: " << git.size() << "\n"; std::cout << "Size of root: " << root.size() << "\n"; return 0; }
The
add_component
is being called frommain
. How can I change that? I don't mind calling it inside a new class calledFileSystem
by creating functions such asmkdir
ormkfile
to handle folder and file creation. But I am not able to come up with a good design.If
FileSystem
is being implemented, I would like to avoid having to take the pointer to parent inside themain
, while creating files and folders. This is again something that is stopping me from coming up with a better design.How to improve the functionalities implemented? Are there any significant issues in this part?
Is a better design possible without changing classes and their interface?
Kindly provide an overall review.
std::filesystem
represents these, or is this a completely independent approach?\$\endgroup\$