I am trying to make this example as natural as possible to make it simple.
Lets say I have groups of items. eg item1, item2, item3, item4 etc.
Currently item is represented by struct:
// only contains data
struct item{
string name;
std::vector<string> parts_name;
std::vector<double> parts_price;
std::vector<string> item_color;
...
};
itemx item1, item2...
Then I have class called items
class items{
public:
// return name of all items
vector<string> get_all_item();
// return price of all parts
vector<double> get_all_parts_price();
private:
// hold vector of item
vector<shared_ptr<item>> list_of_items;
// name of item and its parts price
// eg: <item_1_part_1, $1.3>
// eg: <item_1_part_2, $2.3>
// eg: <item_2_part_1, $4.3>
map<string, double> parts_prices;
};
The problem with my current items class is that it is growing really huge,
as feature of item increases.
My solution: make struct item contain function which distributes load
to struct item from class items.
Is there any other better way or any design pattern that is meant for this kind of problem?
It is hard to tell you how to "design" your application based on your input - and I think you are focusing on the wrong aspect here. Your item struct contains vectors. That implies plural. But still, the class is called item.
In that sense: don't think about patterns here. Instead, step back and have a much closer look at the "real world things" you intend to model. You see, the core point of objects and classes is to built a model of the domain you are dealing with.
So a non-answer here: carefully look into the "real-world" relation that your objects have, and then focus on creating a OO model that is helpful to do work flows you intend to implement.
Related
I am creating a sort of "interactive dictionary". The dictionary will be composed of WORDS (as entries), obviously. So I defined what a 'word' is : a series of elements : a main English word, a list of synonyms, a list of antonyms, a translation in French etc...
So far, I have created a "WORD WIDGET" which contains all these fields.
My wordBank List will therefore contain a "List of Word Widgets".
I was wondering if it is a good way to organize the data, of if a list of MAPS would be better ?
Will there be a difference in performance when using the list, sorting, getting elements etc... ?
This is the way I structured it :
enum Nature {
nom_masc,
nom_fem,
adjectif,
adverbe,
verbe,
verbe_irr,
preposition,
}
class Word {
final int id;
final Nature nature;
final String theme;
final List<String> french; // the first element is the primary word
final List<String> english; // the first element is the primary word
final String image;
final String sound; // to be used as label2 in case of input type question
final String wDef; // a written definion of the main word
final String oDef; // an oral definition of the main word
final String phon; // a phonetic transcription of the word
Word({
#required this.id,
#required this.nature,
#required this.theme,
#required this.french,
#required this.english,
this.image,
this.sound,
this.wDef,
this.oDef,
this.phon,
});
}
```
Always prefer a list of core data instead of a list of UI widgets. There are a lot of advantages :
It always a good practice to keep your backend and frontend decoupled.
Keeping a List of Maps will help you to re-use the data in that list anywhere in your app. Like say you want to make another list of the same data but the widget design will be different or maybe you only want to display some of the data in the map, these conditions can be easily satisfied by a list of Map than a list of widgets.
Compare the data types of each. An object of Map type will take less space as it only contains the data. But on the other hand, an object of a Widget will take up a lot of space depending on the depth and child widgets of widget tree.
If you keep a list of Maps, it will be easy to customize your resultant list view. Say while displaying the ListView you want to give a different color to the child widget based on the some other data present on the same page. It will be a lot easier and simpler to execute using a List of Map.
There are many more advantages plus it keeps the code clean and easy to manage.
Based on what I understood from your description, there are few things worth mentioning:
Don't have a list of widgets rather have any data structure to store the data (List, Map anything depends on the use case) and wrap it into a widget while displaying them to the user.
Now to store this data based on your use case, using a map can be beneficial as it can reduce the search time when you are querying any word you want as in the dictionary, there is only a unique word with a particular spelling. A list is suitable for storing any data when you don't have any special condition (like dictionary here) on the data stored in it, so a linear search is performed every time you search for an element.
So you can have a map of words (String) to word object and based on the word you want, you can query that map, retrieve the data and wrap that data into the WordWidget while displaying it to the user.
Also, as a general practice in software development, we try to keep things as loosely decoupled as possible. So, a layer (or data structure) that provides data should only serve this purpose and a layer that takes data and wraps it into a UI element should be separate. This way your code will be maintainable and extendible too based on any future use case.
During my C++ exam I found I had some difficulties with what is probably supposed to be something relatively simple. I think I am overlooking something on my problem. For the sake of not getting in trouble for posting part of an exam online, I will make a very simple representation of the part I had troubles with.
What was expected was to make a class myClass in which i could add items item. Then i was supposed to be able to make lists of some items i wanted in that list. The amount of items able to be in the list should be infinite. Each list should have a certain (unique) name. I am also told not to make a new class for the lists and to choose the right container myself.
myClass::myClass(){
itemlist= {};
lists= {};
}
void myClass::addItem(Item &item){
itemlist.emplace_back(item);
}
void myClass::makeList(string listname){
vector <Item> list = {};
// list .name = listname
lists.emplace_back(list);
}
void myClass::addItemToList(string listName, Item &item){
for (int i=0; i<lists.size; i++){
if lists[i].name == listName {
lists.emplace_back(item);
return;
}
}
}
I don't know how to link a name to a list without creating a new class for the lists. I thought about storing another list containing the names of the lists and using that, but it seemed wrong to do so, as they aren't actually linked then. Tried to look up if there is a way to make a list variable listname from the string listname parameter, but apparently that's not possible.
As for the containers, I chose a vector as they can store an "infinite" amount of data in it. I use the itemlist to store all items ever added to myClass, and lists to store all the lists ever created.
In what way is it possible to store a name for each list and for it to be linked?
I think the simplest way to name lists is to use std::unordered_map http://en.cppreference.com/w/cpp/container/unordered_map
Then you'll be able to use your lists like this:
lists["first_list"].push_back(...);
lists["another_list"].size();
lists["create_new_list"] = {};
Maybe what you are looking for "link a name to a list" is a std::map
Something like
std::map<std::string, std::vector<Item>>
Now I have :
struct vote
{
int user; // ID of the user
int item; // ID of the item
float value; // Rating
};
typedef struct vote vote;
And testVotes iterates this data type:
std::set<vote*> testVotes;
Given the testVotes pointing to the vote data contains the information that a certain user give a certain rating to a certain item. Now I want to get the items which the user, let's say, the first user(user id =1) has not rated yet.
In addition, as this code is written by others, and there has been thousands of lines already, I do not prefer to change the existing struct. How can I do what I want without changing the existing code?
Thank you in advance!
------------------------------new demand-----------------------------------
given a known element user id, 3, and another known element item id, 5, how can I get the corresponding element value (3, 4, ?) ?
If looking for the solution for a single specific user a function could build an std::set of all items that him/her rated:
std::set<int> rated_items(int user) {
std::set<int> result;
for (auto p : testVotes) {
if (p->user == user) result.insert(p->item);
}
}
however if you need to do this for all users then building a single map from users to rated items would be more efficient:
std::map<int, std::set<int>> rated_items() {
std::map<int, std::set<int>> result;
for (auto p : testVotes) {
result[p->user].insert(p->item);
}
}
Knowing which items a user rated makes trivial to know which items the user has NOT rated.
PS: the data structure std::set<vote *> looks a very questionable choice (a std::set<vote> would seem much more reasonable, or an std::vector<vote> if the same user can rate the same item multiple times).
Thousands of lines already written is nothing compared to the grief of living forever with a bad data structure.
You really should spend several days to read much more about Programming using C++ and about C++ standard containers.
You might have some map or set indexed by user ids (e.g. have some appropriate class userdata then use std::map<int,userdata> and/or std::set<int> with the int key being the user id).
Contrarily to your claims, if you are working in a team, you should consider (after discussion with co-workers) to improve the data structure and the existing code (so patching the struct vote should be discussed and attempted, and you should consider patching the code at other places too!). A version control system like git facilitate doing that.
Perhaps you should use smart pointers, for example by declaring std::set<std::shared_ptr<vote>> testVotes; or you just want a set of votes std::set<vote> testVotes;
I am basically having to make a program that will generate a PDF. The PDF will have 3 different page types: a front cover sheet, a general sheet, and a last cover sheet. The header contains a fair amount of information but the header of the front cover sheet and the general sheet only differ by 1 item, however, that one items requires me to shift the others down in coordinates. I have a picture attached to show what I mean.
Also the only purpose the classes are really serving is holding values to represent rectangles that will be used as targets to print text in the pdf. So they really have no need of any functionality aside from the constructor with only initializes the values from a file of constants.
I am trying to use "good" design practice but I am uncertain of what a more efficient method is. It doesn't seem like I can use inheritance that shares the common elements as I will always end up with something I don't need in one of the classes. I thought about just using composition and making a class for each element in the header, that would solve the problem, but then I would have a lot more classes and it would be a class with just to hold one data member which doesn't seem efficient.
So I would just appreciate any suggestions on how to make this a more cohesive and sensible design.
The picture is NOT what I have currently but it is to represent that the data I need seems to be coupled awkwardly or perhaps I am just over complicating this.
Front sheet, general sheets and back sheet have in common that they ARE sheets. A good candidate for your class hierarchy would therefore be:
class sheet { .... };
class front_sheet : public sheet { ...};
class back_sheet : public sheet { ...};
class general_sheet : public sheet { ...};
In sheet, you should put all the common elements, and of course the common behaviour (e.g. print(), save(), get_size(), ...).
There should be a member function that calculates the position of an element in a page. As the rule depends on the kind of page, it would be a virtual function of sheet(), and front and back sheets could overide the default function. This approach will help you to easily manage the different layout of the different pages.
class sheet {
public:
virtual void get_position (int item_no, int& x, int&y) { x=5; y=14*item_no; }
...
};
class back_sheet : public sheet {
public:
void get_position (int item_no, int& x, int&y) { x=5; y = (item==5 ? 14:0); }
...
};
As inheritance really corresponds to a "is-a" relationship, you'll have get a very robust design.
You should however think about the content of your sheet. I see here two main orientations:
you could manage items in a container (e.g. vectors) : it's easier to organise your output in loops instead of copy pasting similar lines of codes for every item
you should ask yourself if the items could have subitems (e.g. a region could contain several subregions, like a print layout with a box and boxes in the box). In this case, i'd recommend the use of the composite pattern
Edit; After having thought about the content, it could be worth coming back again to the sheets, and ask yourself how much different their behaviour really is:
do they have different behaviour thorughout their lifecycle (different way to acquire data for PDF generation or to use dynamically the layout ? In which case the class hierarchy would be ok.
or, after having adopted a dynamic structure such as one suggested above, does it turn out that the only difference is the way you create/construct them ? In this case, it could be worth thinking to keep only one sheet class after all, but having three construction "engines", using either the prototype pattern or the builder pattern. This would however be a significant shift in your application's architecture.
Edit: I called it association because in my head it should be this, but it seems that I implement it as an aggregation... This can be also discussed...
Context
What you learn in IT is that when you do associations, you should use pointers.
For example: You have 2 objects: Person and Movie. One Person can do several Movie and one Movie can be done by/with several Person. You would then have:
class Person
{
public:
Person::Person();
int id;
vector<Movie*> movies;
};
class Movie
{
public:
Movie::Movie();
int id;
};
main()
{
Person person;
Movie *movie = new Movie;
person.movies.push_back(movie); // With a setter it would be better but...
}
or something like this (please correct me if I do something wrong =D)
Where the troubles appear
Now you have many persons and movies and you want to save it somewhere: in a database.
You get your person
You get all the movies it is associated with in order to construct the whole object.
But how do you get them?
Do you reconstruct a new pointer of Movie for each Person concerned that you associate ?
You lose then the association property that allow the objects to be linked but live their own life.
Do you load all the database in RAM and... ok forget this
What is the way to do it cleverly? What is the proper way given by documentations?
I'm interested in simplified/pseudo code as examples, dissertation... Thx a lot !
Your question is very broad, and there's a number of approaches, how to bind database tables (and represent their foreign key connections).
It's not really only how to represent/handle that kind of Domain Model snippet, you're presenting in your code sample here.
#Martin Fowler provided the EAA pattern catalogue you could reasonably research, and apply appropriate patterns for these kind of object <-> relational mapping problems you address.