Reputation: 13313
I have two classes
class PopulationMember
{
public:
void operationOnThisMember1();
void operationOnThisMember2();
...
private:
Population* populaltion_;
}
class Population
{
public:
void operationOnAllMembers1();
void operationOnAllMembers2();
...
void operationOnAllMembers100();
void sortAllMembersCriterium1();
void sortAllMembersCriterium2();
...
void sortAllMembersCriterium100();
private:
QVector<PopulationMember*> members_;
}
I would like to implement a SELECT-like functionality to my framework. That is be able to perform operations only on those members which share a certain combination of properties.
So far I have thought out two approaches:
Implement a method that would return a new Population object composed of Members that satisfy a certain condition.
Popuation Popuation::select(bool (predicate*) (PopulationMember*));
Add a
bool selected_;
flag to each PopulationMember.
If I do 1. There is no way to implement sorting of selected data and deletion. If I do 2. There is overhead with checking for selectedness and I would have to reimplement sorting and other algorithms to operate only on selected members.
Is there a third, better way?
Upvotes: 2
Views: 2365
Reputation: 7858
This is a proposal based on something similar i had to do once, which is an extended form of your first approach. The advantage is the usage of STL's concepts and the freedom to either implement many functors or few parametrizable functors.
class All
{
public:
bool operator()(const PopulationMember* entity) const
{
return true;
}
};
class AscByID
{
public:
bool operator()(const PopulationMember* a, const PopulationMember* b) const
{
return a->getId() < b.getId();
}
};
template<typename Entity, class Predicate, class SortComparator>
class Query
{
public:
typedef std::set<Entity, SortComparator> ResultSet;
Query(const Predicate& predicate = Predicate(), const SortComparator& cmp = SortComparator()) :
predicate(predicate), resultSet(cmp)
{
}
bool operator()(const Entity& entity)
{
if (predicate(entity))
{
resultSet.insert(entity);
return true;
}
return false;
}
const ResultSet& getResult(void) const
{
return resultSet;
}
void clearResult(void)
{
resultSet.clear();
}
private:
Predicate predicate;
ResultSet resultSet;
};
int main()
{
Query<const PopulationMember*, All, AscByID> query;
Popuation::execute(query);
//do something with the result
query.getResult();
//clear the result
query.clearResult();
//query again
Popuation::execute(query);
//do something useful again
return 0;
}
Upvotes: 1
Reputation: 57774
I have never looked, but I expect it will be method 1. See the MySQL source code to confirm my expectation. :-)
Upvotes: 1
Reputation: 153840
The approach I would take is to expose an iterator interface to the entire collection. To implement some sort of selection I would then use iterator adapters, e.g. one taking a unary predicate, which provide a new view of the range. This way there is neither an impact on the stored object nor any overhead in creating a separate collection. If you look at Boost's iterator adapters you may already get pretty much what is needed.
Upvotes: 2