8
\$\begingroup\$

I have a Queue class that is basically a single linked list. It has 2 remove methods. What would be the cleanest way to avoid duplication of the code? Only the comparisons in methods are different.

int Queue::remove(const string& substring)
{
 // Loop through the queue list
 size_t found;
 found = current_job->description.find(substring)
 if (found != string::npos) {
 // Remove job.
 }
 // Return the amount of removed jobs. 
}
int Queue::remove(int priority)
{
 // Loop through the queue list
 if (current_job->priority == priority) {
 // Remove job.
 }
 // Return the amount of removed jobs. 
}

I thought a template solution as answered here, but in this case, the comparison function has different arguments.

asked Mar 11, 2012 at 13:05
\$\endgroup\$

2 Answers 2

11
\$\begingroup\$

You can abstract out the thing that changes, the comparison expression, into a predicate for a template function.

class PriorityMatch
{
 int priority_;
public:
 explicit PriorityMatch(int priority)
 : priority_(priority) {}
 bool operator()(const Job& job)
 {
 return job->priority == priority_;
 }
};
class DescriptionMatch
{
 std::string substring_;
public:
 explicit DescriptionMatch(const std::string& substring)
 : substring_(substring) {}
 bool operator()(const Job& job)
 {
 return job->description.find(substring_) != std::string::npos;
 }
};
template<class Predicate>
int Queue::remove(Predicate predicate)
{
 // Loop through the queue list
 if (predicate(current_job)) {
 // Remove job.
 }
 // Return the amount of removed jobs. 
}
int Queue::remove(const string& substring)
{
 return remove(DescriptionMatch(substring));
}
int Queue::remove(int priority)
{
 return remove(PriorityMatch(substring));
}

Or in C++11:

template<class Predicate>
int Queue::remove(Predicate predicate)
{
 // Loop through the queue list
 if (predicate(current_job)) {
 // Remove job.
 }
 // Return the amount of removed jobs. 
}
int Queue::remove(const string& substring)
{
 return remove([](const Job& job){
 return job->description.find(substring) != std::string::npos;
 });
}
int Queue::remove(int priority)
{
 return remove([](const Job& job){
 return job->priority == priority;
 });
}
answered Mar 11, 2012 at 16:19
\$\endgroup\$
3
  • \$\begingroup\$ +1. The only difference; I usually make simple functors like PriorityMatch and DescriptionMatch private member structures rather than classes. This is because I do not seem them as real object but rather as property bags that are used to transport information to a call site. \$\endgroup\$ Commented Mar 11, 2012 at 17:00
  • \$\begingroup\$ @LokiAstari: What do you mean? The struct and class keywords are almost synonyms. \$\endgroup\$ Commented Mar 11, 2012 at 19:25
  • \$\begingroup\$ @AntonGolov: I use struct for property bags. Its not anything major just a stylistic thing that I have adopted. \$\endgroup\$ Commented Mar 11, 2012 at 22:31
0
\$\begingroup\$

Just to add a comment, I think that renaming both member functions to Queue::removeBySubstring and Queue::removeByPriority could improve code readability at the client side.

answered May 17, 2012 at 20:55
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.