Which design pattern should I use in this case? - c++

I have a class named DS which can (1) read a data from file and accordingly build a data structure from scratch, or (2) read a pre-built data structure from file. I originally wrote:
class DS
{
DS(std::string file_name, bool type);
}
where file_name is the file to read and type specifies what we are reading, data or pre-built data structure. This method is not very elegant, as far as I am concerned. I also tried the following:
class DS
{
DS(std::string file_name);
void CreateFromData();
void ReadExisting();
}
But because modification is not allowed once built, I do not want the user to first call CreateFromData and then ReadExisting.
Are there some design patterns to address this issue?

Use static factory functions if the constructor signature isn't semantic enough. No need to get fancy with it.
class DS {
private:
enum class Source { FromExisting, FromData };
DS(const std::string& path, Source type);
public:
static DS ReadExisting(const std::string& path) {
return DS(path, Source::FromExisting);
}
static DS CreateFromData(const std::string& path) {
return DS(path, Source::FromData);
}
};
/* ... */
DS myData = DS::ReadExisting("...");

Here's how I'll do it:
Create two sub classes from a new DataFetch class - CreateFromData and ReadExisting; all three having getData method. Create another 'Data manager" class which will have instance of DataFetch, It would Data Manager's responsibility to create appropriate object based on "User" input, you could have two constructors for that. Now, Your DS's constructor will take Data manager's object, created in previous step and ask it to filling current DS object, via getData method.
This allows your design to add more types of data fetching later on, whilst removing any coupling from your DS and data fetching.

Essentially, as the user of DS you input a file path and expect to get back a data structure corresponding to the file’s content. You should not have to worry about the data format in the file at all. That’s an implementation detail of the storage format and should be a part of the loading logic.
So, this is what I would do:
Put a format ID at the beginning of each data file, identifying which storage format it uses. Or maybe even different file extensions are sufficient.
When reading the file the format ID determines which concrete loading logic is used.
Then the user of DS only has to provide the file name. The storage format is transparent.
Ideally you simplify the API and get rid of DS. All your caller sees and needs is a simple function:
// in the simplest case
OutputData load_data_from_file(const std::string& filepath);
// for polymorphic data structures
std::unique_ptr<IOutputData> load_data_from_file(const std::string& filepath);
That fits the use-case exactly: “I have a path to a data file. Give me the data from that file.”. Don’t make me deal with file loader classes or similar stuff. That’s an implementation detail. I don’t care. I just want that OutputData. ;)
If you only have the two current storage formats and that’s unlikely to change, don’t overcomplicate the logic. A simple if or switch is perfectly fine, for instance:
OutputData load_data_from_file(const std::string& filepath)
{
const auto format_id = /* load ID from the file */;
if (format_id == raw) {
return /* call loading logic for the raw format */;
}
else if (format_id == prebuilt) {
return /* call loading logic for the prebuilt format */;
}
throw InvalidFormatId();
}
Should things become more complicated later you can add all the needed polymorphic file loader class hierarchies, factories or template magic then.

Option 1: Enumeration Type
You essentially have two different modes for reading the data, which you differentiate via the parameter bool type. This is bad form for a number of reasons, not the least of which being that it's unclear what the two types are or even what type true refers to vs false.
The simplest way to remedy this is to introduce an enumeration type, which contains a named value for all possible types. This would be a minimalistic change:
class DS
{
enum class mode
{
build, read
};
DS(const std::string &file_name, mode m);
};
So then we could use it as:
DS obj1("something.dat", DS::mode::build); // build from scratch
DS obj2("another.dat", DS::mode::read); // read pre-built
This is the method that I would use, as it's very flexible and extensible if you ever want to support other modes. But the real benefit is clarity at the call site as to what's happening. true and false are often obscure when used as function arguments.
Option 2: Tagged Constructors
Another option to differentiate these functions which is common enough to mention is the notion of tagged constructors. This effectively amounts to adding a unique type for each mode you want to support and using it to overload the constructors.
class DS
{
static inline struct built_t {} build;
static inline struct read_t {} read;
DS(const std::string &file_name, build_t); // build from scratch
DS(const std::string &file_name, read_t); // read pre-built
};
So then we could use it as:
DS obj1("something.dat", DS::build); // build from scratch
DS obj2("another.dat", DS::read); // read pre-built
As you can see, the types build_t and read_t are introduced to overload the constructor. Indeed, when this technique is used we don't even name the parameter because it's purely a means of overload resolution. For a normal method we'd typically just make the function names different, but we can't do that for constructors, which is why this technique exists.
A convenience I added was defining static instances of these two tag types: build and read, respectively. If these were not defined we would have to type:
DS obj1("something.dat", DS::build_t{}); // build from scratch
DS obj2("another.dat", DS::read_t{}); // read pre-built
Which is less aesthetically pleasing. The use of inline is a C++17 feature that makes it so that we don't have to separately declare and define the static variables. If you're not using C++17 remove inline and define the variables in your implementation file as usual for a static member.
Of course, this method uses overload resolution and is thus performed at compile time. This makes it less flexible than the enumeration method because it cannot be determined at runtime, which would conceivably be needed for your project later down the road.

Related

How to share global constants with minimum overhead at runtime?

I am using C++11. I am not allowed to use external libraries like boost etc. I must use STL only.
I have a number of events, which must be identified as string constants. I am not allowed to use enums or ints or any other data type. For example:
"event_name1"
"event_name2"
"some_other_event_name3"
"a_different_event_name12"
Then I have some classes which need to use these strings, but don't know the other classes exist (they don't have anything to do with each other).
class Panel{
void postEvent(){
SomeSingleton::postEvent("event_name");
}
}
Another class::
class SomeClass{
SomeClass(){
SomeSingleton::listenForEvent("event_name");
}
void receiveEvent(){
//This function is triggered when "event_name" occurs.
//Do stuff
}
}
All these events are constants, and are used to identify things that are happening.
Here is what I have tried:
How to store string constants that will be accessed by a number of different classes?
Some of the persons there suggested I provide specific details of how to solve a concrete problem, so I have created this new question.
How can I store the strings in a common file, so that all the other classes that use these strings can refer to the same file?
I do not want to waste memory or leak memory during my app's lifetime (it is a mobile app)
compilation times are not a big deal to me, since the project isn't so big
there are expected to be maybe 50 different events.
It seems it would be more maintainable to keep all the strings in one file, and edit only this file as and when things change.
Any class can listen for any event, at any time, and I won't know prior to compilation
The easiest way would be to use a char const* constant, as it's way more optimizable and don't use dynamic allocations.
Also you can use std::string_view in the postEvent function, avoiding dynamic allocations. This step is optional. If you cannot have string views and still want to avoid dynamic allocations, then refer to your implementation's SSO max capacity and keep event names below that size.
Also consider that nonstd::string_view can be shipped as a C++11 library and most likely the abstraction you need. Library such as cpp17_headers and string-view-lite exist solely for that purpose.
It look like this:
constexpr auto event_name1 = "event_name1";
In a class as a static member it works the same way:
struct Type {
static constexpr auto event_name1 = "event_name1";
};
This will at most take space in the read-only static data of your executable.
In light of the fact that you're stuck with C++11, I think my suggestion from here still stands:
#ifndef INCLUDED_EVENT_NAMES
#define INCLUDED_EVENT_NAMES
#pragma once
namespace event_names
{
constexpr auto& event_1 = "event_1";
constexpr auto& event_2 = "event_2";
}
#endif
Defining named references to string literal objects is very simple, does not require any additional libraries, is guaranteed to not introduce any unnecessary objects, won't require any additional memory over the storage for the statically-allocated string literal objects that you'd need anyways, and will not have any runtime overhead.
If you could use C++17, I'd suggest to go with the std::string_view approach, but in C++11, I think the above is most-likely a good compromise for your application.
Global const std::string has one drawback it need processing during startup and creates copy of string literal.
The linked SO answear uses constexpr std::string_view and this is cool solution since constructor is constexpr so nothing have to be done on startup. Also it doesn't create any copy. Problem is that this is C++17
Use of const char [] (or auto or constexpr) is old proven solution. You can compare std::string with it without any extra overhead.
You can create header file for all that strings and let linker to remove all duplicates. It was working like that in old C++.
You can have a struct of static strings:
struct MyNames
{
static const std::string name1;
};
And in a cpp:
const std::string MyNames::name1 = "foo";
You can then access the names from all your required locations. In C++17, you would have used string_view instead to avoid object construction. But this seems to be a duplicate of this answer, basically: https://stackoverflow.com/a/55493109/2266772
For the sake of proper abstraction and good design, you should define an event class. This event class will have either:
A method which provide a string (e.g. name() or system_name())
A conversion operator to a string (not recommended)
A to_string() freestanding function which takes such an event (not recommend)
But beyond that - all of your class can now use an enum, or an index, or whatever they like - they'll just need to use the conversion method whenever they interact with whatever it is that requires strings. Thus none of your classes has to actually know about those strings itself.
The strings themselves can stay within the .cpp implementation file of the class, and nobody else has to know about them. (unles they are actually defined in code that's not yours, but that's not how you described the problem.)

What is the best C++ design to contain a class's objects?

I have a class with many objects that I would like to group in some type of container and also access them with some type of identifier.
class Menu {
Object title;
Object play;
Object instructions;
Object pause;
...
};
Having each object listed in the class, shown above, is nice because I can access them like, menu.title, but then I have to retype every name to add it to a container, vector.push_back(title).
Shown below is how I've always solved the problem. I use an enum's integer value to access the corresponding index. objects[TITLE] or objects[PLAY]
class Menu {
std::vector<Object> objects;
};
enum ObjectTypes {
TITLE, PLAY, INSTRUCTIONS, PAUSE, ...
};
I generally dislike this approach because it seems indirect, and when using nested classes and enums, the identifiers can become long and cumbersome. I'm coming from C and somewhat new to C++. Does anybody have a more practical and/or elegant way to solve this problem? C++11 and above welcomed!
The approach you are using is fine. If you want to avoid cumbersome identifiers, you can make a temporary reference to keep things more succinct. For example, instead of calling:
menu.objects[PAUSE].foo();
menu.objects[PAUSE].bar();
menu.objects[PAUSE].baz();
... you could do this when necessary:
Object & pause = menu.objects[PAUSE];
pause.foo();
pause.bar();
pause.baz();
and it would work the same, but without all of the redundant characters.
I think your approach is fine. Using a std::map<ObjectType, Object> instead of a std::vector might be a little more type-safe.
Either way, if you want to save yourself a little typing you could overload the operator[] on Menu:
Object& operator[](index_type i){ return objects[i]; }
const Object& operator[](index_type i) const { return objects[i]; }
Then you can write menu[TITLE].
Other than that, I don't see how it can be any less cumbersome, there is no redundant information there and, as Jeremy pointed out, if you need an object multiple times you can always create a local reference auto& title = menu[TITLE];.
Depending on what other responsibilities Menu has maybe you don't need a Menu class at all and you can just use a map or vector directly?
The best solution to your question depends mostly on your use cases.
I see two main use cases:
You want to represent "functions"of a "device" so you can achieve readable code when manipulating that "device" from your code. Such as a MediaPlayer device having play, stop, pause operations. But you dismissed the option to simply add member functions to your "device" object, such as Play(), because you want to re-use your play code also for another device, such as a tuner device. Also, you want to apply operations to all or a sub set of those "functions", for example Enable()/Disable()/ToString()/Trigger(),Configure()..., which is why the member function approach is not favorable.
You want to create a Document Object model, which is more data focused. Such as an Xml Document.
From what you wrote in your question, I assume you have use case 1 in mind. Your Object type has all the common operations you need.
Yet, then there are the differences between all those "functions".
In order to stick to your simple approach, you would need to manually set up/configure your Object instances, which might in the long run turn out to be annoying, but hardly avoidable:
// Example of "annoying": If you have more than 1 "device",
// you have to write such a function for each of them.
// Also, there is that fishy bit with Object.Id - the association between
// your configuration data and your object you want to configure.
void ConfigureMenu( std::vector& menuItems, MenuConfigurationData& configData )
{
for( auto& menuItem : menuItems )
{
menuItem.Configure( configData[menuItem.Id] ); // spoiler!
}
}
Also, I am inclined to think that even now you have some code not shown in your question, which configures your objects.
With that in mind, you might want to get rid of the idea to write 1 class type per "device" by hand. The next device/menu will need to be treated the same, yet with dedicated more coding.
So, my advice to you is to get rid of your class Menu for good, to abstract your problem and to model your problem rather like: Object is your "function" and a device is simply a set of functions/Objects. Then, your class Menu simply becomes an instance, named Menu.
typedef uint32_t FunctionId; // for example uint32_t...
typedef std::map<FunctionId,Object> Device; // aka. Menu.
Then, in the configuration function you most likely have anyway, you pass in an instance of that Device map and your configuration function fills it with Object, properly configured.
// those enums are still specific to your concrete device (here Menu) but
// you can consider the time it takes writing them an investment which will
// pay off later when you write your code, using your functions.
// You assign the function id which is used in your meta-data.
enum class MenuFunctions : FunctionId { play = ..., title = ..., instructions, ... };
// "generic" configuration function.
// Does not only configure your Object, but also puts it inside the device.
void ConfigureDevice( Device& device, ConfigData& configData )
{ // ...
}
And later in your code, you can access the functions like this:
menu[MenuFunctions::play].Trigger();
There are alternative approaches and variations to this, of course. For example, assuming you have your meta data (config data, device descriptions), you could stop coding all that by hand and instead write some code generator which does the job for you.
Your first version of such a generator could create your configuration functions and the enums for you.
With all that in place, the use case of "nested classes" becomes just a matter of creating collections of Device instances. Now, as all your devices are of the same type, you can compose and sub-group them at your leisure.
A few different approaches below. I'm not saying which is "best". There are pros/cons to them all.
A) Rather than using a vector (e.g. class Menu { std::vector<Object> objects; };), use an array class Menu {std::array<Object,NObjectTypes> objects;}; when your element count is constant.
B) Just use a class, but provide an api to return a std::array<> of references to your objects:
class Menu {
Object title;
Object play;
Object instructions;
Object pause;
...
std::array<Object*,NObjects> allObjects();
};
C) std::tuple can be useful when your types are not all the same.
For menus, I'll often go with "A".

A use for boost::any?

I'm not sure if this calls for boost::any. I'd rather use native templates if there's a pattern that does what I want. I have this class (which I've written here using boost::any) defined in a header:
template <typename T> class Observable;
class Report
{
typedef unordered_map<wstring, std::shared_ptr<Observable<boost::any>>> ObservationMap;
public:
void AddObservable(const wstring& name, std::shared_ptr<Observable<boost::any>> observable);
const Observable<boost::any>& GetObservable(const wstring& name) const;
protected:
ObservationMap observations;
};
and Observable is defined like this:
template <typename T>
struct Observable
{
typedef T Type;
T Quantity;
// ...
};
I would really like some way of adding Observables of any quantity type to Reports. Is there a more effective way of doing this without incurring the overhead of boost::any?
Edit: An example of code that adds observables to the report class would be something like this:
Observable<float> obs1;
obs1.Quantity = 1.1f;
Observable<int> obs2;
obs2.Quantity = 5;
Report report;
report.AddObservable("Height", obs1);
report.AddObservable("Age", obs2);
Then somewhere else I would want to read those quantities. Say I receive the report:
void DoSomethingWithReport(Report& report)
{
float height = report.GetObservable("Height").Quantity;
int age = report.GetObservable("Age").Quantity;
}
Something like that. Of course, I'd really add other methods to check if those observations are present in the report, etc. I prefer it to be generic because I don't know beforehand, at the receiving site, what it will contain, so I'd like some flexibility.
boost::any is a decently efficient way to store a value of a type you have prevented the compiler (for whatever reason or design requirement) from knowing.
If there are only a limited set of operations you want to perform on the data, you can use type erasure instead and/or a base interface class. But that requires knowing all uses for the data when you define the interface.
If you have a limited set of data types, boost::variant or the like can be more efficient than any. You can even have a variant that includes any or a type erasure object (or objects) in the set of types.
You can use reflection or similar techniques to store complex data and wrap it in any accessors (or variant) if your data is sometimes structured, which can reduce storage overhead somewhat. Basically structured data becomes a type erased type with member access by name.
Much of these techniques end up mirroring type behaviour of scripting or bytecode languages: sometimes it might be a good idea to write the part of your app that needs this amount of compile time flexibilty in a mainly runtime type checked language.
Finally you may decide you do not need all this needless runtime dynamic typing.

Should I prefer a const function?

Assume I want to implement class A which must load its "configuration" from a file. And let's assume the "configuration" is a simple map<string, string>.
I can implement the A::LoadConfiguration in two different ways:
void A::LoadConfiguration(string filename)
map<string, string> A::LoadConfiguration(string filename) const
Should I prefer either of the two implementations, and why?
If you prefer the second version when the user wants to get info on a file they will base all their algorithms on the map. If you do the second version, meaning the implementation may be a map, but doesn't have to be, they can base their code around an API which does not have to change even if the internal implementation does.
Consider the situation where later you realize it is far more efficient to use an std array, for whatever reason, now every program using this code has to change many of it's algorithms. Using the first version the change to array can be handled internally and reflect no changes on the outside.
Now if you are planning to make multiple instances of the class you will definitely want to make it a static method because you don't want the file to load every time you call the constructor (especially if the file will not change).
Completely ignoring your suggestions, but this is probably how I would do it (not knowing all your constraints, so ignore me if it does not fit):
class A
{
public:
static A fromConfiguration( string fileName );
/* ... */
}
In most cases, the "configuration" of a class should be set at object creation, so forcing the user to provide it on construction is a good thing (instead of having to remember to do do the loading later).
namespace NeatStuff
{
map<string,string> loadSimpleConfiguration( string fileName );
}
If the configuration file format is really simple (and not specific to your class) you can move the actual loading out of the class.
Assuming other classes use the configuration later, I prefer option 1, and an additional GetConfigurationParameter public const method that gets the config value for a particular key. That lets me make other classes which can just ask for some parameter by name without ever caring that it's implemented as a map.
Another reason why I prefer option 1 is that loading a configuration should be distinct from returning it. If I see a name like LoadConfiguration, I assume that it loads the config from somewhere and sets the parameters in the class. I do not assume it returns some description of the configuration, which I'd instead expect from a method like GetConfiguration - but opinions on this will vary for different people of course.

How to perform type scanning in C++?

I have an ESB. Any serialized message transports its own fully qualified name (that is, namespace + class name). I have a concrete type for each message that encapsulates a specific logic to be executed.
Every time I receive a message, I need to deserialize it at first, so I can perform its operations --once more, depending on its concrete type--.
I need a way to register every single class at compile time or during my application initialization.
With .net I would use reflection to scan assemblies and discover the message types during initialization, but how would you do it in C++?
C++ has no reflection capability. I suppose you could try to scan object files, etc., but there's no reliable way to do this (AFAIK); the compiler may entirely eliminate or mangle certain things.
Essentially, for serialization, you will have to do the registration (semi-)manually. But you may be interested in a serialization library that will help out with the chores, such as Boost Serialization.
Since there is no reflection in C++, I would suggest using an external script to scan your source code for all relevant classes (which is easy if you use empty dummy #defines to annotate them in the source code) and have it generate the registration code.
I personally use the manual registration road. If you forget to register... then the test don't work anyway.
You just have to use a factory, and implement some tag dispatching. For example:
typedef void (*ActOnMessageType)(Message const&);
typedef std::map<std::string, ActOnMessageType> MessageDispatcherType;
static MessageDispatcherType& GetDispatcher() {
static MessageDispatcherType D; return D;
}
static bool RegisterMessageHandler(std::string name, ActOnMessageType func) {
return GetDispatcher().insert(std::make_pair(name, func)).second;
}
Then you just prepare your functions:
void ActOnFoo(Message const& m);
void ActOnBar(Message const& m);
And register them:
bool const gRegisteredFoo = RegisterMessageHandler("Foo", ActOnFoo);
bool const gRegisteredBar = RegsiterMessageHandler("Bar", ActOnBar);
Note: I effectively use a lazily initialized Singleton, in order to allow decoupling. That is the registration is done during the library load and thus each Register... call is placed in the file where the function is defined. The one difference with a global variable is that here the dispatching map is actually constant once the initialization ends.