Implementing UML Sequence Diagram - c++

My question is relatively simple: how would I go about implementing a UML sequence diagram in C++ code? I was reading up on sequence diagrams the other day, and I found this example for a program for a student enrolling in a seminar.
How would I go about turning this diagram into a program? For the sake of this question, lets focus on one class, say the EnrollInSeminar controller. How would I go about implementing this?
I imagine that it might be something like this:
class EnrollInSeminar
{
public:
void Activate();
};
void EnrollInSeminar::Activate()
{
SecurityLogon logonUI{};
Student theStudent = logonUI.getStudent();
SeminarSelector seminarSelectorUI{};
Seminar seminar = seminarSelectorUI.getSeminar();
if (!seminar.isEligible(theStudent))
return;
theStudent.getSchedule().determineFit(seminar);
Fee fee = StudentFees.calculateFees(seminar, theStudent);
FeeDisplay feeUI{fee};
if (!feeUI.getVerification())
return;
seminar.enrollStudent(theStudent);
}
Is this the correct way to implement the EnrollInSeminar class? If not, how should I do it?

Actually a SD does not tell anything about the methods being used in the messages passed from one object to another except the name, the parameters and - as the name says - the sequence. So the only thing you can draw from "just the SD" are methods and their parameters.
You will need additional information from a use case to know what the methods are all about. Without you simply can not "implement a SD".

Related

OOP for global system/task monitoring class

I'm trying to create a performance monitor of sorts to run on a Particle board (STM32 based). I'm used to programming in c so the OOP approach is a bit new but I think it would fit well here.
For the purpose of this question let's assume I have two types of monitors:
Frequency. The application can call a "tick" method of the monitor to calculate the time since it last ran and store it.
Period- call a "start" and "stop" method of the monitor to calculate how long a process takes to run and store it.
What I would like to do is to create instances of these monitors throughout my application and be able to report on the stats of all monitors of all types from the main module.
I've read about the singleton design pattern which seems like it might be what I need but I'm not sure and I'm also concerned about thread safety with that.
I'm thinking I will create a "StatMonitor" class and a derived class "FrequencyMonitor" and "PeriodMonitor". Monitor would be a singleton and everywhere I wanted to create a new monitor I would request an instance of "Monitor" and use that like so:
freqMonitor * task1FreqMonitor = StatMonitor::GetInstance()->Add_Freq_Monitor("Task1");
The StatMonitor would track all monitors I've added and when I wanted to print the stats I could just call the printAll method which would iterate it's array of monitors and request their results like so:
StatMonitor::GetInstance()->PrintAllStats();
Am I going down the right path?
Your path sounds good, except that FrequencyMonitor and PeriodMonitor should not derive from the class that "manages" all these monitors (let's call it MonitorPrinter).
MonitorPrinter should be a singleton and could look like this:
class MonitorPrinter
{
public:
static MonitorPrinter& getInstance()
{
static MonitorPrinter monitorPrinter;
return monitorPrinter;
}
void printAllStats()
{
for (const auto& [_, frequencyMonitor] : _frequencyMonitors)
frequencyMonitor.print();
for (const auto& [_, periodMonitor] : _periodMonitors)
periodMonitor.print();
}
FrequencyMonitor& getFrequencyMonitor(std::string name)
{ return _frequencyMonitors[name]; }
PeriodMonitor& getPeriodMonitor(std::string name)
{ return _periodMonitors[name]; }
private:
MonitorPrinter() = default;
std::map<std::string, FrequencyMonitor> _frequencyMonitors;
std::map<std::string, PeriodMonitor> _periodMonitors;
};
Demo
(The const auto& [_, frequencyMonitor] is a structured binding).
FrequencyMonitor and PeriodMonitor should not have anything to do with singletons, and from your description, they need not be part of a class hierarchy either (as they have different interfaces). If you want, you can prevent users (other than the MonitorPrinter) from instantiating these classes using other techniques, but I won't elaborate on that here.
In short, there is no need to use OOP here. Use a singleton to provide (and keep track of) the monitors, and implement the monitors to your liking. Be wary of thread safety if this is relevant (the above is not thread-safe!).

Project structure in C++ in relation to publicly exposed headers

I am trying to understand project structure in c++, I am finding it difficult to get my head around class structure and header files.
Extract from article 1 (linked at bottom of this post)
By convention, include directory is for header files, but modern practice > suggests that include directory must strictly contain headers that need
to be exposed publicly.
My first question of this process is with regards to a separate class file that is within the include directory.
What is purpose of exposing your headers?
Following on from this, looking at an example of an exposed header file. Linked in the following GH repo: https://github.com/AakashMallik/sample_cmake
How does the Game_Interface class relate back to the Game_Engine?
game_interface.h
#pragma once
#include <game_engine.h>
class GameInterface
{
private:
GameEngine *game;
public:
GameInterface(int length);
void play(int num);
};
I have looked else where for a simple explanation of this process but, all I have found so far is nothing that can be understood in the context of this example.
Fairly new to C++ background in web technologies.
Link to article 1: https://medium.com/heuristics/c-application-development-part-1-project-structure-454b00f9eddc
What is purpose of exposing your headers?
Sometimes you may be developing some functionality or a library. You might want to help some other person or customer or client by sharing the functionality of your code. But you don't want to share the exact working details.
So for instance you wish to share an Image processing functionality which applies beautiful filters to it. But at the same time you don't want them to exactly know how did you implement it. for such scenarios, you can create a header file, say img_filter.h having function declaration -
bool ApplyFilter(const string & image_path);
Now you can implement entire details in img_filter.cpp:
bool ApplyFilter(const string & image_path)
{
....
// Implementation detail
...
}
Next you can prepare a dll of this file which could be used by your client. For reference of working, parameters, usage etc. you can share the img_filter.h.
Relation with Interface:
A well defined interface is generally nice to have so you can change implementation details transparently, which means, that HOW you implement the details don't matter as long as the interface or the function name and parameters are kept intact.

User Input parsing for keywords C++

I'm getting back into programming for the first time in over a decade and I'm a little rusty in C++.
I decided to make a zork type game that has a text based user prompt for all player actions but I wanted to parse the string input (i'm using getline(cin,MyString)) for keywords and interprete the desire of the user. I'm looking to have some sort of alias so that if user types any of the following: yes, y, Yes, Yesir, Yessem, Yep, Uh-Huh, etc that it will interprete it as "yes" and not have a giant case statement. I'm going to have this for a number of keywords and I want to easily add more.
I'm looking to have the game compare the keyword to a list of keywords in a text file and determine what the base keyword to use so I can determine an action from their input.
Are there any established libraries or practices that I could use for this functionality?
Currently looking at something like this:
Get user input
Check user input for keywords
Put each keyword into a class
assign class variable for the alias aka Keyword.type()="yes" or Keyword.type()="north"
Perform action based on keywords
Any help would be greatly appreciated.
Let's say you have an action class for all possible cases.
class Action
{
public:
virtual void doAction(YourGame*)=0;
};
class YesAction : public Action
{
public:
void doAction(YourGame* game) {/* your yes logic */}
};
class NoAction : public Action
{
public:
void doAction(YourGame* game) {/* your no logic */}
};
Then, in your YourGame, have a std::map<std::string, Action*> actionMap.
Action* yesAction = new YesAction();
actionMap["yes"] = yesAction;
actionMap["yep"] = yesAction;
actionMap["yeah"] = yesAction;
When you get user input, use actionMap.find(userInput) to get the possible action, and if it's not actionMap.end() (which means no such action), call doAction of the Action instance you get.
You'd also want to have functions such as isValid that checks whether the given action is valid for the current state in YourGame. doAction may call YourGame functions, or even change states.
Have you looked at Ternary search tree?
An implementation is here.

C++ class for managing the access to database

The question is more a Best way of doing question than a real problem.
Context and what I'm doing
I have an application that must access to the database. Therefore I have a class DatabaseManager that is called every time I need to access the database and which does for instance:
DatabaseManager *db = new DatabaseManager;
std::vector<Element> elementVector = db->getAElementsById(id);
And you the same for all insert, update or remove requests.
What eventually happened...
...is that my file has already 1200 lines and is growing with every new feature.
The question
So how do pretty people do ?
One header several splitted files? (This told that it's not a good idea)
Splitting the class in several class? The databaseManager is one class, it would be a nonsense...
Is there any other option? (I'm not familiar with the notion of namespace, maybe is it a way?)
I read also other post but didn't find either the good question to ask google, or people answering my question.
I have my database module split into more than one file. For example, one file handles insertions, another file handles extractions and a third handles searches.
Mine is actually more complex, but the practice should be to split up the code into separate themed files, preferably no more than 300 LOC (Lines Of Code).
The solution I chose for now is the following (because I was too lazy to reconstruct new classes and so on) : I splitted the class in several cpp files
// DatabaseManager.h
class DatabaseManager
{
//// Getters - in DatabaseManager_getters.cpp
public:
// Movies
Movie getOneMovieById(const int id);
QList<Movie> getAllMovies(const QString fieldOrder = "title");
....
private:
// Other functions for getters
Movie hydrateMovie(QSqlQuery &query);
//// Inserts - in DatabaseManager_insert.cpp
public:
bool insertNewMovie(Movie &movie);
....
private:
bool insertNewTag(Tag &tag);
....
//// Updates - in DatabaseManager_update.cpp
public:
bool updateMovie(Movie &movie);
....
//// Delete - in DatabaseManager_delete.cpp
public:
bool deleteMovie(Movie &movie);
private:
bool deletePeople(const People &people);
};
And obviously the .cpp files are following what announced. It's easier for me to find where a function is and to maintain the code.
Another time, I'll think twice if it's not more relevant to follow the advices you gave.
Thx again !

What is a good typesafe alternative to variadic functions in C++?

In joint with this question. I am having trouble coming up with a good type safe solution to the following seemingly basic problem. I have a class music_playlist that has a list of the songs it should play. Seems pretty simple right, just make an std::list of all the songs in queue, and make it available to the user. However, out of necessity the audio decoding, and the audio rendering happens on separate threads. So the list needs to be mutex protected. Often times the mutex was forgotten by other programmers using my library. Which obviously led to "strange" problems.
So at first I just wrote setters for the class.
struct music{};
class music_playlist{
private:
std::list<music> playlist;
public:
void add_song(music &song){playlist.push_back(song);}
void clear(){playlist.clear();}
void set_list(std::list<music> &songs){playlist.assign(songs.begin(),songs.end());}
//etc
};
This led to user code like below...
music song1;
music song2;
music song3;
music song4;
music song5;
music song6;
music_playlist playlist1;
playlist1.add_song(song1);
playlist1.add_song(song2);
playlist1.add_song(song3);
playlist1.add_song(song4);
playlist1.add_song(song5);
playlist1.add_song(song6);
//or
music_playlist playlist2;
std::list<music> songs;
songs.push_back(song1);
songs.push_back(song2);
songs.push_back(song3);
songs.push_back(song3);
songs.push_back(song5);
songs.push_back(song6);
playlist2.set_list(songs);
While this works and is very explicit. It is very tedious to type out and it is bug prone due to all the cruft around the actual work. To demonstrate this, I actually intentionally put a bug into the above code, something like this would be easy to make and would probably go through code reviews untouched, while song4 never plays in playlist 2.
From there I went to look into variadic functions.
struct music{};
class music_playlist{
private:
std::list<music> playlist;
public:
void set_listA(music *first,...){
//Not guaranteed to work, but usually does... bleh
va_list Arguments;
va_start(Arguments, first);
if (first) {
playlist.push_back(first);
}
while (first) {
music * a = va_arg(Arguments, music*);
if (a) {
playlist.push_back(a);
}else {
break;
}
}
}
void set_listB(int count,music first,...){
va_list Arguments;
va_start(Arguments, first);
playlist.push_back(first);
while (--count) {
music a = va_arg(Arguments, music);
playlist.push_back(a);
}
}
//etc
};
Which would lead to a users code like below...
playlist1.set_listA(&song1,&song2,&song3,&song4,&song5,&song6,NULL);
//playlist1.set_listA(&song1,&song2,&song3,&song4,&song5,&song6); runtime error!!
//or
playlist2.set_listB(6,song1,song2,song3,song4,song5,song6);
Now its much easier to see if a song was added twice or not included. However in solution A it will crash if NULL is not at the end of the list, and is not cross platform. In solutionB you have to count the amount of arguments which can lead to several bugs. Also, none of the solutions are type safe, and the user could pass in an unrelated type and wait for the crash at runtime. This didn't seem to be a sustainable solution. So then I came across std::initializer_list. Can't use it several of the compilers I develop for don't have support for it yet. So I tried to emulate it. I ended up with this solution below.
Is this use of the "," operator considered bad form?
Which would lead to a users code looking like this...
struct music_playlist{
list<music> queue;
//...
};
int main (int argc, const char * argv[])
{
music_playlist playlist;
music song1;
music song2;
music song3;
music song4;
playlist.queue = song1,song2; // The queue now contains song1 and song2
playlist.queue+= song1,song3,song4; //The queue now contains two song1s and song2-4
playlist.queue = song2; //the queue now only contains song2
return 0;
}
This syntax was not confusing to our small testgroup. However, I had serious concerns with abusing operator overloading so severely. So I posted the question above. I wanted to see what programmers that were comparatively experts to our test group thought. Quite alot of programmers did not like it however it seemed better than the above solutions because it would catch most bugs at compile time instead of just at run time. However Tom posted an interesting counter example, that would cause unexpected behavior.
//lets combine differnt playlists
new_playlist.queue = song1 //the first playlist
,(song3,song4) //the second playlist //opps, I didn't add song 3!
, song5;
This sours me to that solution. So do you have any ideas about a better solution?
P.S. None of the above code was compiled, they are just there for example purposes.
The first question that comes to mind is whether this is a problem, and whether this is a problem worth the solution. Since you are creating an interface, your client will be user code (not people, code). How many times will your clients hardcode playlists in the code versus say, store load them from a file or construct them from their user selections?
Think on the actual value of the feature and compare that with the impact that it will have in how they use your library, and think on how many problems your users might have with the changed interface.
The simplest solution is accepting iterators to construct/reset your list, and then let the users deal with the problem. Of course they can build their own container in the way that you have shown, but they can also use Boost.Assignment to take care of the boiler plate, so their user code will look like:
std::vector<music> songs = boost::assign::list_of()( song1 )( song2 );
play_list.set( songs.begin(), songs.end() );
Or if they are not comfortable with that library the can use a plain old array:
music songs[2] = { song1, song2 };
play_list:set( songs, songs + 2 ); // add your preferred magic to calculate the size