From bc02054d56118110a36aea72d21f9d5e73d07d1f Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Tue, 22 Oct 2024 14:00:41 +0200 Subject: refactor file reading factory --- FileReader.cpp | 9 +++---- FileReader.h | 17 ++++++------- FileReaderFactory.cpp | 40 +++++++++++++---------------- FileReaderFactory.h | 15 ++--------- HTTPFileReader.cpp | 16 +++--------- HTTPFileReader.h | 17 +++---------- LoadFilesCommand.cpp | 2 +- LocalFileReader.cpp | 27 ++++++++------------ LocalFileReader.h | 20 ++++++--------- docs/class-diag.puml | 69 +++++++++++++++++++++++++++++++-------------------- 10 files changed, 98 insertions(+), 134 deletions(-) diff --git a/FileReader.cpp b/FileReader.cpp index b76de50..89ebe17 100644 --- a/FileReader.cpp +++ b/FileReader.cpp @@ -1,9 +1,6 @@ -#include - #include "FileReader.h" -#include "FileReaderFactory.h" -FileReader::FileReader(const std::string protocol) { - FileReaderFactory::register_strategy(protocol, this); -} +using namespace std; + +FileReader::FileReader(const string & url) : url(url) { } diff --git a/FileReader.h b/FileReader.h index f896ec8..ee6e550 100644 --- a/FileReader.h +++ b/FileReader.h @@ -5,21 +5,20 @@ class FileReaderFactory; #include class FileReader { -protected: - virtual void open(const std::string url) = 0; -public: - virtual void close() = 0; - virtual const std::string read() = 0; + friend class FileReaderFactory; +protected: + FileReader(const std::string & url); public: virtual ~FileReader() = default; protected: - FileReader() = default; - virtual FileReader * clone() const = 0; + virtual void open() = 0; +public: + virtual void close() = 0; + virtual const std::string read() = 0; protected: - FileReader(const std::string protocol); - friend FileReaderFactory; + const std::string url = ""; }; diff --git a/FileReaderFactory.cpp b/FileReaderFactory.cpp index 4b72b11..e40dbb9 100644 --- a/FileReaderFactory.cpp +++ b/FileReaderFactory.cpp @@ -3,34 +3,28 @@ #include "FileReaderFactory.h" #include "FileReader.h" +#include "LocalFileReader.h" +#include "HTTPFileReader.h" + using namespace std; -unique_ptr FileReaderFactory::open(const std::string url) { - FileReader * reader = find_reader(url)->clone(); - reader->open(url); - return unique_ptr(reader); -} +unique_ptr FileReaderFactory::create(const string & url) { + FileReader * reader = nullptr; -void FileReaderFactory::register_strategy(const std::string type, const FileReader * node) { - static FactoryMap & map = get_map(); - map[type] = node; -} + // protocol handlers + if (url.starts_with("file://")) + reader = new LocalFileReader(url); + else if (url.starts_with("http://")) + reader = new HTTPFileReader(url); + else if (url.starts_with("https://")) + reader = new HTTPFileReader(url); -FactoryMap & FileReaderFactory::get_map() { - static FactoryMap map; - return map; -} - -const FileReader * FileReaderFactory::find_reader(const std::string type) { - static FactoryMap & map = get_map(); + // no protocol = treat as file:// + if (reader == nullptr) + reader = new LocalFileReader(url); - // try to find protocol by prefix - for (auto item : map) { - if (!type.starts_with(item.first)) continue; - return item.second; - } + reader->open(); - // fallback is local file - return map.find("file://")->second; + return unique_ptr(reader); } diff --git a/FileReaderFactory.h b/FileReaderFactory.h index 0829985..85521c0 100644 --- a/FileReaderFactory.h +++ b/FileReaderFactory.h @@ -1,27 +1,16 @@ #pragma once #include -#include #include #include "FileReader.h" -using FactoryMap = std::map; - class FileReaderFactory { public: - static std::unique_ptr open(const std::string url); + std::unique_ptr create(const std::string & url); -private: +public: FileReaderFactory() = default; virtual ~FileReaderFactory() = default; - -private: - static void register_strategy(const std::string type, const FileReader * node); - static FactoryMap & get_map(); - static const FileReader * find_reader(const std::string type); - -private: - friend FileReader; }; diff --git a/HTTPFileReader.cpp b/HTTPFileReader.cpp index d7f5dd4..191e212 100644 --- a/HTTPFileReader.cpp +++ b/HTTPFileReader.cpp @@ -2,10 +2,10 @@ #include "HTTPFileReader.h" -HTTPFileReader HTTPFileReader::instance(protocol); +using namespace std; -void HTTPFileReader::open(const std::string url) { - _res = cpr::Get(cpr::Url{url}); +void HTTPFileReader::open() { + _res = cpr::Get(cpr::Url{this->url}); } void HTTPFileReader::close() { } @@ -14,13 +14,3 @@ const std::string HTTPFileReader::read() { return _res.text.data(); } -HTTPFileReader::~HTTPFileReader() { - this->close(); -} - -HTTPFileReader * HTTPFileReader::clone() const { - return new HTTPFileReader(this); -} - -HTTPFileReader::HTTPFileReader(const HTTPFileReader *) : FileReader() { } - diff --git a/HTTPFileReader.h b/HTTPFileReader.h index 4b05e18..59a8599 100644 --- a/HTTPFileReader.h +++ b/HTTPFileReader.h @@ -5,24 +5,15 @@ #include "FileReader.h" class HTTPFileReader : FileReader { + friend class FileReaderFactory; + using FileReader::FileReader; + protected: - virtual void open(const std::string url); + virtual void open(); public: virtual void close(); virtual const std::string read(); -public: - virtual ~HTTPFileReader(); - -private: - HTTPFileReader(const HTTPFileReader *); - virtual HTTPFileReader * clone() const; - -private: - using FileReader::FileReader; - constexpr static const std::string protocol = "https://"; - static HTTPFileReader instance; - private: cpr::Response _res; }; diff --git a/LoadFilesCommand.cpp b/LoadFilesCommand.cpp index 82ede60..3fb4978 100644 --- a/LoadFilesCommand.cpp +++ b/LoadFilesCommand.cpp @@ -28,7 +28,7 @@ void LoadFilesCommand::load_files() { MuseumDeserializer deserializer { this->museum }; for (string url : files) { - unique_ptr file = FileReaderFactory::open(url); + unique_ptr file = FileReaderFactory().create(url); try { ParserFactory::parse(*file, deserializer); } catch (Exception & e) { diff --git a/LocalFileReader.cpp b/LocalFileReader.cpp index 1f9d574..a505616 100644 --- a/LocalFileReader.cpp +++ b/LocalFileReader.cpp @@ -1,17 +1,18 @@ #include +#include #include #include "LocalFileReader.h" #include "Exception.h" -LocalFileReader LocalFileReader::instance(protocol); +using namespace std; -void LocalFileReader::open(const std::string url) { - std::string path = url; - if (path.starts_with(protocol)) - path = path.substr(protocol.size()); +void LocalFileReader::open() { + string path = this->url; + if (path.starts_with("file://")) + path = path.substr(strlen("file://")); - this->file = new std::ifstream(path, std::ios::in); + this->file = new ifstream(path, ios::in); if (this->file->fail() || !this->file->is_open()) throw Exception("cannot open file://%s\n", path.c_str()); } @@ -23,7 +24,7 @@ void LocalFileReader::close() { this->file->close(); } -const std::string LocalFileReader::read() { +const string LocalFileReader::read() { if (this->content != nullptr) return *this->content; @@ -33,9 +34,9 @@ const std::string LocalFileReader::read() { if (!this->file->is_open()) throw Exception("FileReader read after close\n"); - this->content = new std::string( - std::istreambuf_iterator(*this->file), - std::istreambuf_iterator() + this->content = new string( + istreambuf_iterator(*this->file), + istreambuf_iterator() ); return *this->content; @@ -55,9 +56,3 @@ LocalFileReader::~LocalFileReader() { } } -LocalFileReader * LocalFileReader::clone() const { - return new LocalFileReader(this); -} - -LocalFileReader::LocalFileReader(const LocalFileReader *) : FileReader() { } - diff --git a/LocalFileReader.h b/LocalFileReader.h index 6ea4f84..b9daa55 100644 --- a/LocalFileReader.h +++ b/LocalFileReader.h @@ -5,23 +5,17 @@ #include "FileReader.h" class LocalFileReader : FileReader { -protected: - virtual void open(const std::string url); -public: - virtual void close(); - virtual const std::string read(); + friend class FileReaderFactory; + using FileReader::FileReader; public: virtual ~LocalFileReader(); -private: - LocalFileReader(const LocalFileReader *); - virtual LocalFileReader * clone() const; - -private: - using FileReader::FileReader; - constexpr static const std::string protocol = "file://"; - static LocalFileReader instance; +protected: + virtual void open(); +public: + virtual void close(); + virtual const std::string read(); private: std::ifstream * file = nullptr; diff --git a/docs/class-diag.puml b/docs/class-diag.puml index 8058e0a..6c38d9c 100644 --- a/docs/class-diag.puml +++ b/docs/class-diag.puml @@ -18,29 +18,31 @@ exception Exception { } rectangle Group_FileReading as "File reading" <> { - class FileReaderFactory <> { - + open(url) : FileReader& + class FileReaderFactory <> { + + create(url : const string &) : uniq } interface FileReader { - + read() : string + # FileReader(url : const string &) + + ~FileReader() + -- + # open() + + read() : const string + close() -- - # open(string url) - # clone() : FileReader* <> + # url : const string } class LocalFileReader { - - instance : LocalFileReader <> + + ~LocalFileReader() } class HTTPFileReader { - - instance : HTTPFileReader <> } package CPR { } - FileReader <|.u. LocalFileReader - FileReader <|.u. HTTPFileReader + FileReader <|.d. LocalFileReader + FileReader <|.d. HTTPFileReader - FileReader .l> FileReaderFactory - FileReader <. FileReaderFactory + FileReaderFactory -u-> LocalFileReader + FileReaderFactory -u-> HTTPFileReader HTTPFileReader -l> CPR @@ -59,20 +61,21 @@ rectangle Group_ParsingDeserialization as "Parsing & deserialization" <> + heuristic(FileReader &) : unsigned int <> } - Parser .> ParserFactory - Parser <. ParserFactory - - class CSVParser class XMLParser class TXTParser + class CSVParser package pugixml { } - CSVParser ..|> Parser - TXTParser ..|> Parser - XMLParser ..|> Parser + Parser <|.d. XMLParser + Parser <|.d. TXTParser + Parser <|.d. CSVParser + + ParserFactory -u-> XMLParser + ParserFactory -u-> TXTParser + ParserFactory -u-> CSVParser - XMLParser -> pugixml + XMLParser -r> pugixml class MuseumDeserializer { + MuseumDeserializer(Museum &) @@ -135,6 +138,7 @@ rectangle Group_Model as "Model" <> { - worker : thread * - work() } + together { class Canvas { + Canvas(Museum &) -- @@ -148,6 +152,10 @@ rectangle Group_Model as "Model" <> { - tiles : vector - museum : Museum & } + struct CanvasData { + + rows : unsigned int + + columns : unsigned int + } class People { + People(Museum &) -- @@ -159,6 +167,8 @@ rectangle Group_Model as "Model" <> { - artist_count : size_t - museum : Museum & } + } + together { class Tile { + data : TileData + color : Color @@ -190,11 +200,9 @@ rectangle Group_Model as "Model" <> { + vx : float + vy : float } - struct CanvasData { - + rows : unsigned int - + columns : unsigned int } + together { struct Color { red : unsigned int green : unsigned int @@ -204,7 +212,9 @@ rectangle Group_Model as "Model" <> { + get_color(string) : Color <> + register_color(string, Color) <> } + } + together { interface TileBehavior { + step(Artist *) + update(Tile &) @@ -214,13 +224,13 @@ rectangle Group_Model as "Model" <> { # interactions : unsigned int # museum : Museum & } - class TileBehaviorFactory { + TileBehaviorFactory(Museum &) + create(string) : uniq -- - museum : Museum & } + } together { class NullTileBehavior { @@ -243,8 +253,15 @@ rectangle Group_Model as "Model" <> { -- - last_interactions : unsigned int } + + NullTileBehavior -d[hidden]- StepTileBehavior + StepTileBehavior -d[hidden]- DeleteArtistTileBehavior + DeleteArtistTileBehavior -d[hidden]- SetNeighborTileBehavior + SetNeighborTileBehavior -d[hidden]- CreateArtistTileBehavior } + Canvas -l[hidden] People + Museum --> People Museum --> Canvas @@ -258,7 +275,7 @@ rectangle Group_Model as "Model" <> { Tile --> "state" Color Tile .[norank].> TileColorFactory - TileColorFactory .> Color + TileColorFactory -> Color TileBehavior <|.. NullTileBehavior TileBehavior <|.. StepTileBehavior @@ -275,9 +292,6 @@ rectangle Group_Model as "Model" <> { Tile --> "state" TileBehavior Tile .[norank].> TileBehaviorFactory - TileBehaviorFactory .l> TileBehavior - TileBehaviorFactory <. TileBehavior - ' LAYOUT Artist -r[hidden] Tile } @@ -378,6 +392,7 @@ rectangle Group_Commands as "Commands" <> { } /' LAYOUT '/ Parser .l> FileReader +' Parser -l> FileReaderFactory MuseumDeserializer .l> Museum Museum --> PathfindingContext -- cgit v1.2.3