我很快为这个问题写了下面的课。
我正在寻找一种将addFruit()
与removeFruit()
合并以减少代码的方法。
它们都使用相同的条件,但最后只是不同的函数调用。
我的代码:
#include <iostream>
#include <string>
#include <vector>
class MyClass
{
public:
void addFruit(const std::string &str, int count)
{
if (str == "apples")
addToVec(apples, count);
else if (str == "oranges")
addToVec(oranges, count);
else if (str == "lemons")
addToVec(lemons, count);
else if (str == "melons")
addToVec(melons, count);
else if (str == "bananas")
addToVec(bananas, count);
else
std::cout << "Unknown Fruit : " << str << '\n';
}
void removeFruit(const std::string &str)
{
if (str == "apples")
removeFromVec(apples);
else if (str == "oranges")
removeFromVec(oranges);
else if (str == "lemons")
removeFromVec(lemons);
else if (str == "melons")
removeFromVec(melons);
else if (str == "bananas")
removeFromVec(bananas);
else
std::cout << "Unknown Fruit : " << str << '\n';
}
private:
void addToVec(std::vector<int> &vec, int count)
{
vec.push_back(count);
}
void removeFromVec(std::vector<int> &vec)
{
vec.pop_back();
}
std::vector<int> apples;
std::vector<int> oranges;
std::vector<int> lemons;
std::vector<int> melons;
std::vector<int> bananas;
};
有什么巧妙的方法可以很好地合并两个函数,以便减少代码量?
答案 0 :(得分:6)
进行其他功能,例如determineTargetVector(const std::string &str)
返回对应的向量,您要在其中插入/删除元素,因此没有多余的条件。每个功能只有一个职责也很高兴。
例如:
std::vector<int> *determineTargetVector(const std::string &str)
{
if (str == "apples")
return &apples;
else if (str == "oranges")
return &oranges;
else if (str == "lemons")
.
.
.
else
//something invalid, to check for in superior function
return nullptr;
}
答案 1 :(得分:3)
最简单的解决方案可能是对这些向量使用std::map
:
std::map<std::string,std::vector<int>> fruitVecs;
地图的键值为"apples"
,"oranges"
,"bananas"
等。
因此,您可以轻松地通过地图访问相应的矢量。
答案 2 :(得分:2)
可以使用选择要使用的向量然后执行操作的代码:
class MyClass
{
public:
void addFruit(const std::string &str, int count)
{
auto vec = selectVector(str);
if(vec != nullptr)
addToVec(*vec, count);
else
std::cout << "Unknown Fruit : " << str << '\n';
}
void removeFruit(const std::string &str)
{
auto vec = selectVector(str);
if(vec != nullptr)
removeFromVec(*vec);
else
std::cout << "Unknown Fruit : " << str << '\n';
}
private:
std::vector<int> *selectVector(const std::string &str)
{
if (str == "apples")
return &apples;
else if (str == "oranges")
return &oranges;
else if (str == "lemons")
return &lemons;
else if (str == "melons")
return &melons;
else if (str == "bananas")
return &bananas;
else
return nullptr;
}
void addToVec(std::vector<int> &vec, int count)
{
vec.push_back(count);
}
void removeFromVec(std::vector<int> &vec)
{
vec.pop_back();
}
std::vector<int> apples;
std::vector<int> oranges;
std::vector<int> lemons;
std::vector<int> melons;
std::vector<int> bananas;
};
答案 3 :(得分:2)
下面的解决方案呢?这也将允许您通过在构造函数中添加/删除行来轻松添加/删除已知水果。
#include <iostream>
#include <string>
#include <vector>
#include <map>
class MyClass
{
public:
MyClass()
{
allowedFruits["apples"] = {};
allowedFruits["oranges"] = {};
allowedFruits["lemons"] = {};
allowedFruits["melons"] = {};
allowedFruits["bananas"] = {};
}
void addFruit(const std::string &str, int count)
{
auto it = allowedFruits.find(str);
if(it != MyClass::allowedFruits.end()){
it->second.push_back(count);
}
else {
std::cout << "Unknown Fruit : " << str << '\n';
}
}
void removeFruit(const std::string &str)
{
auto it = allowedFruits.find(str);
if(it != allowedFruits.end()){
// my be some check here
it->second.pop_back();
}
else {
std::cout << "Unknown Fruit : " << str << '\n';
}
}
private:
std::map<std::string,std::vector<int>> allowedFruits;
};
答案 4 :(得分:1)
无需更改界面,您可以这样做:
std::vector<int>& pickVector(std::string str) {
// put all the switch here and return a reference to the correct vector
}
void addFruit(const std::string &str, int count)
{
addToVec(pickVector(str),count);
}
答案 5 :(得分:1)
我会通过传递要应用的功能来简化功能。
#include <iostream>
#include <string>
#include <vector>
#include <functional>
class MyClass
{
public:
void addFruit(const std::string &str, int count)
{
searchAndApplyHelper(str, std::bind(&MyClass::addToVec, *this, std::placeholders::_1, count));
}
void removeFruit(const std::string &str)
{
searchAndApplyHelper(str, std::bind(&MyClass::removeFromVec, *this, std::placeholders::_1));
}
private:
template <class Func>
void searchAndApplyHelper(const std::string str, Func f)
{
if (str == "apples")
f(apples);
else if (str == "oranges")
f(oranges);
else if (str == "lemons")
f(lemons);
else if (str == "melons")
f(melons);
else if (str == "bananas")
f(bananas);
else
std::cout << "Unknown Fruit : " << str << '\n';
}
void addToVec(std::vector<int> &vec, int count)
{
vec.push_back(count);
}
void removeFromVec(std::vector<int> &vec)
{
vec.pop_back();
}
std::vector<int> apples;
std::vector<int> oranges;
std::vector<int> lemons;
std::vector<int> melons;
std::vector<int> bananas;
};
我使用模板来做,但是您也可以使用std::function
。
答案 6 :(得分:0)
使用C ++ 17,您可以使用可选参数:
mb_*
和:
void addRemoveFruit(const std::string &str, std::optional<int> count = std::nullopt)
{
if (str == "apples")
addRemoveVec(apples, count);
else if (str == "oranges")
addRemoveVec(oranges, count);
else if (str == "lemons")
addRemoveVec(lemons, count);
else if (str == "melons")
addRemoveVec(melons, count);
else if (str == "bananas")
addRemoveVec(bananas, count);
else
std::cout << "Unknown Fruit : " << str << '\n';
}
这样,只需将现有对void addRemoveVec(std::vector<int> &vec, std::optional<int> count = std::nullopt)
{
if(count.has_value()) {
vec.push_back(count.value());
} else {
vec.pop_back();
}
}
/ addFruit
的调用更改为removeFruit
,而不必更改传递的参数。
答案 7 :(得分:0)
我会这样做:
class MyClass
{
public:
void addFruit(const std::string &str, int count)
{
doToFruit(str, [&](std::vector<int> &vec){ addToVec(vec, count); });
}
void removeFruit(const std::string &str)
{
doToFruit(str, [&](std::vector<int> &vec){ removeFromVec(vec); });
}
private:
template<typename Callable>
void doToFruit(const std::string &str, const Callable &func)
{
std::pair<const char*, std::vector<int>&> fruits[] = {
{"apple", apples}, {"oranges", oranges}, {"lemons", lemons},
{"melons", melons}, {"bananas", bananas}
};
for (auto i : fruits)
if (str == i.first)
return func(i.second);
std::cout << "Unknown Fruit : " << str << '\n';
}
void addToVec(std::vector<int> &vec, int count)
{
vec.push_back(count);
}
void removeFromVec(std::vector<int> &vec)
{
vec.pop_back();
}
std::vector<int> apples;
std::vector<int> oranges;
std::vector<int> lemons;
std::vector<int> melons;
std::vector<int> bananas;
};
如果您想获得更好的性能,可以使用pointer to members:
class MyClass
{
public:
void addFruit(const std::string &str, int count)
{
doToFruit(str, [&](std::vector<int> &vec){ addToVec(vec, count); });
}
void removeFruit(const std::string &str)
{
doToFruit(str, [&](std::vector<int> &vec){ removeFromVec(vec); });
}
private:
template<typename Callable>
void doToFruit(const std::string &str, const Callable &func)
{
auto iFound = fruits.find(str);
if (iFound != fruits.end())
func(this->*(iFound->second));
std::cout << "Unknown Fruit : " << str << '\n';
}
void addToVec(std::vector<int> &vec, int count)
{
vec.push_back(count);
}
void removeFromVec(std::vector<int> &vec)
{
vec.pop_back();
}
std::vector<int> apples;
std::vector<int> oranges;
std::vector<int> lemons;
std::vector<int> melons;
std::vector<int> bananas;
static std::unordered_map<std::string, std::vector<int> MyClass::*> fruits;
};
std::unordered_map<std::string, std::vector<int> MyClass::*> MyClass::fruits = {
{"apple", &MyClass::apples}, {"oranges", &MyClass::oranges},
{"lemons", &MyClass::lemons}, {"melons", &MyClass::melons},
{"bananas", &MyClass::bananas}
};
答案 8 :(得分:-1)
要坚持使用多个不同向量的模式,我建议使用一个内部枚举来确定方法,而向量的选择可以在一个地方完成:
class MyClass
{
public:
void addFruit(const std::string &str, int count)
{
addOrRemoveFruit(str, count, Method::ADD);
}
void removeFruit(const std::string &str)
{
addOrRemoveFruit(str, 0, Method::REMOVE);
}
private:
enum class Method
{
ADD,
REMOVE
};
void addOrRemoveFruit(const std::string &str, int count, Method method)
{
if (str == "apples")
addOrRemoveFruitImpl(apples, count, method);
else if (str == "oranges")
addOrRemoveFruitImpl(oranges, count, method);
else if (str == "lemons")
addOrRemoveFruitImpl(lemons, count, method);
else if (str == "melons")
addOrRemoveFruitImpl(melons, count, method);
else if (str == "bananas")
addOrRemoveFruitImpl(bananas, count, method);
else
std::cout << "Unknown Fruit : " << str << '\n';
}
void addOrRemoveFruitImpl(std::vector<int> &vec, int count, Method method)
{
if (method == Method::ADD)
vec.push_back(count);
else
vec.pop_back();
}
std::vector<int> apples;
std::vector<int> oranges;
std::vector<int> lemons;
std::vector<int> melons;
std::vector<int> bananas;
};
但是使用地图会更好:
class MyClass
{
public:
void addFruit(const std::string &str, int count)
{
fruits[str].push_back(count);
}
void removeFruit(const std::string &str)
{
if (fruits.count(str) > 0)
fruits[str].pop_back();
}
private:
std::unordered_map<std::string, std::vector<int>> fruits;
};