我很难说出来,但我说有一些功能:
a = a + b;
printf("HI THERE");
b = a + c;
(假装这是30行而不是3行)。现在说我想稍后再做同样的事情,除了打印“HI THERE”我打印“HO THERE”。我目前所做的是复制粘贴此函数的所有行只是为了将HI THERE更改为HO THERE。对于大型代码块,这不是很优雅。
我知道一个解决方案可能就像:
adder_function(1);
adder_function(2);
void adder_fuction(int input) {
a = a + b;
printer_function(input);
b = a + c;
}
void printer_function(int input) {
if (input == 1) printf("HI THERE");
if (input == 2) printf("HO THERE");
}
但对于更复杂的代码块,这似乎也不够优雅。有什么想法可以提供更好的解决方案吗?
编辑:只是为了展示我正在做什么,这里是有问题的代码(你可以看到除了.input和.output以及printf语句之外几乎没有任何变化):
found=line.find("INPUTS");
if (found == 0) {
inputfound = true;
found = line.find_first_of(":");
if (found == string::npos) {
printf("BAD NETLIST INPUT DECLARATION\n\r");
exit(1);
}
found = line.find_first_not_of("\n\t ",found+1);
if (found == string::npos) {
printf("BAD NETLIST INPUT DECLARATION\n\r");
exit(1);
}
else {
temp_node_name += line[found];
for (i = found+1; i < line.size(); i++) {
if ( isalnum(line[i]) || isspace(line[i]) ) {
if ( isalnum(line[i]) )
temp_node_name += line[i];
if ( isspace(line[i]) || i == line.size() - 1 ) {
if (!temp_node_name.empty()) {
if (determine_uniqueness(temp_node_name)) {
nodes.push_back(dummy_node);
nodes.at(id_counter).name_in_netlist = temp_node_name;
nodes.at(id_counter).input = true;
temp_node_name.erase();
id_counter++;
}
}
}
}
else {
printf("BAD NETLIST INPUT DECLARATION\n\r");
exit(1);
}
}
}
printf("NETLIST INPUT DECLARATION OK\n\r");
continue;
}
单独代码块被复制
found=line.find("OUTPUTS");
if (found == 0){
outputfound = true;
found = line.find_first_of(":");
if (found == string::npos) {
printf("BAD NETLIST OUTPUT DECLARATION\n\r");
exit(1);
}
found = line.find_first_not_of("\n\t ",found+1);
if (found == string::npos) {
printf("BAD NETLIST OUTPUT DECLARATION\n\r");
exit(1);
}
else {
temp_node_name += line[found];
for (i = found+1; i < line.size(); i++) {
if ( isalnum(line[i]) || isspace(line[i]) ) {
if ( isalnum(line[i]) )
temp_node_name += line[i];
if ( isspace(line[i]) || i == line.size() - 1 ) {
if (!temp_node_name.empty()) {
if (determine_uniqueness(temp_node_name)) {
nodes.push_back(dummy_node);
nodes.at(id_counter).name_in_netlist = temp_node_name;
**nodes.at(id_counter).output = true;**
temp_node_name.erase();
id_counter++;
}
}
}
}
else {
printf("BAD NETLIST OUTPUT DECLARATION\n\r");
exit(1);
}
}
}
printf("NETLIST OUTPUT DECLARATION OK\n\r");
continue;
}
答案 0 :(得分:2)
制作函数当然是重用代码的好方法。如果在多个位置重复使用相同的代码,则可以使用它来创建一个函数。如果您发现有很多函数在做类似的事情,也许您可以将它们组合成一个具有一些额外参数的函数。在您给出的示例中,您可以执行以下操作:
void adder_function(const char * message) {
a = a + b;
printf("%s", message);
b = a + c;
}
int main() {
adder_function("HI THERE");
adder_function("HO THERE");
}
我建议您尽量避免在源代码中添加幻数(例如1和2)。如上所述,最好使用#defines或完全避免这种情况。
答案 1 :(得分:2)
遵循单一责任原则,您应该将您的代码分解为较小的部分。在您的示例中,您将UI代码(printf)与计算逻辑混合在一起。避免这样做。
由于您使用普通C代码(无C ++)进行讨论,因此很难为您提供使用常见OOP模式的更灵活设计的示例。但对于您的问题,一个非常简单的第一个解决方案是从计算中分离输出内容:
void ShowMessage(const char* msg);
int Calculate(int a, int b);
int DoTheHiThereCalculation()
{
int c = Calculate(1, 2);
ShowMessage("Hi THERE");
return c;
}
答案 2 :(得分:1)
由于这里提出的各种简单解决方案似乎没有用,我会提出一把大锤(警告:谨慎使用)
OO语言中有两种设计模式可以处理模式重复:
在您的情况下,我建议您以依赖注入的方式尝试Strategy
模式。
struct Strategy {
virtual void setFoo(Foo& foo, int i) = 0;
virtual void setBar(Bar& bar, int i) = 0;
};
struct A: Strategy {
virtual void setFoo(Foo& foo, int i) { foo.a = i; }
virtual void setBar(Bar& bar, int i) { bar.a = i; }
};
struct B: Strategy {
virtual void setFoo(Foo& foo, int i) { foo.b = i; }
virtual void setBar(Bar& bar, int i) { bar.b = i; }
};
void doSomething(Foo& foo, Bar& bar, Strategy& strategy) {
for (size_t i = 0; i < 10; ++i) {
//
strategy.setFoo(foo, i);
//
for (size_t j = 0; j < 10; ++j) {
//
strategy.setBar(bar, j);
//
}
}
}
您现在可以使用doSomething
或A
策略调用B
。例如:
int main(int argc, char* argv[]) {
if (argc == 1) { std::cerr << "usage: %prog STRAT\n"; return 1; }
Foo foo;
Bar bar;
char const strat = argv[1][0];
switch(strat) {
case 'a': case 'A': {
A a;
doSomething(foo, bar, a);
return 0;
}
case 'b': case 'B': {
B b;
doSomething(foo, bar, b);
return 0;
}
default:
std::cerr << "Unknown Strategy: " << strat << ", pick A or B\n";
return 2;
}
}
答案 3 :(得分:1)
我迟到了,所以我只会解决你的更新代码。
首先,我看到您将错误消息打印到stdout
(通过printf
),然后调用exit
。为什么?您应该将错误(可能是调试)消息打印到stderr
(fprintf(stderr, ...)
或perror
,但如果库例程失败并设置perror
,errno
会更好})。此外,由于这是C ++(不是普通的C),您可能希望使用iostream
而不是*printf
。它更多是C ++ - ish(尽管,主要是C程序员,我更喜欢*printf
)。
由于两个代码块之间的唯一区别是第一个包含INPUT
而第二个包含OUTPUT
的字符串,我建议将所有这些内容填充到一个函数中,以及其他必要的参数(无论line
可能是其中之一),采用名为bool is_input
的参数。第一次调用时,is_input
应为true
,第二次应为false
。
然后,在两个代码块中,您可以将printf
行更改为:
fprintf(stderr, "BAD NETLIST %s DECLARATION\n", is_input ? "INPUT" : "OUTPUT");
或
fprintf(stderr, "NETLIST %s DECLARATION OK\n", is_input ? "INPUT" : "OUTPUT");
然后为成员修改写:
(is_input ? nodes[id_counter].input : nodes[id_counter]) = true
(注意,没有必要连续两次使用.at
具有相同的索引 - 如果它抛出异常一次,它将不会到达第二个调用,如果它没有抛出第一个时间它不会抛出第二个。它可能不会是一个巨大的加速,但这是重要的想法?)
最后,如果您需要设置外部变量inputfound
和outputfound
,请在您的函数中添加bool &found
参数,并将其设置为true
功能。第一次调用它时,传递inputfound
,第二次传递outputfound
。
现在你的两个代码块是相同的,可以放在一个函数中,并调用两次(一次使用"INPUT"
,一次使用"OUTPUT"
)。容易。
将来,每当您发现自己编写的代码块与另一个代码块非常相似时,请停止重写(或复制并粘贴)。将代码块全部复制到一个新函数中,并通过调用新函数替换原始块。现在,您可以根据需要重复使用该代码块。
答案 4 :(得分:0)
const char* STR_TABLE[N] =
{
"HI THERE",
"HO THERE",
...
};
printf(STR_TABLE[n]);
答案 5 :(得分:0)
根据主题入门评论
。如果我想做一些像node_struct.XXXXX = 2; XXXXXX可以是一个任意字符串,我该怎么做呢?
就你使用c / c ++而言,你可以使用宏。 (看here)
#define NODE_MEMBER(x) node_struct.##x
......
NODE_MEMBER(a)
NODE_MEMBER(b)
答案 6 :(得分:0)
尝试将(在2个函数中)更改的内容作为参数传递给函数(这是唯一接受这些不同参数的函数)。这样,你可以在一个函数中完成这两件事。
答案 7 :(得分:0)
最简单的情况:如果只是改变中间操作的参数,只需将它们作为参数传递给函数(普通C就足够了):
void adder_fuction(const char *text) {
a = a + b;
puts(text);
b = a + c;
}
int main() {
adder_function("HI THERE");
adder_function("HO THERE");
}
现在如果不是,你会想传递一个功能。有很多方法。第一种是传递函数指针(普通C仍然足够):
void adder_function(void (*callback)()) {
a = a + b;
callback();
b = a + c;
}
void callback1() {
puts("HI THERE");
}
void callback2() {
puts("HO THERE");
}
int main() {
adder_function(&callback1);
adder_function(&callback2);
}
您当然可以使用参数和返回值进行回调。 E.g:
void adder_function(int (*callback)(const char *)) {
a = a + b;
c = c + callback("HI THERE");
b = a + c;
}
int callback1(const char *) ...
现在,普通C的最后一个选项是使用预处理器。它应该被认为是一个丑陋的黑客,但是如果你在普通的C中做一些非常通用的东西它确实有它的位置:
#define define_adder_function(name, code) \
name() { \
a = a + b; \
code; \
b = a + c; \
}
由于C宏不卫生,它允许以下内容:
define_adder_function(adder_function1, c = 22) // NO semicolon here. Using preprocessor does have it's quirks
int main() {
adder_function1();
}
现在C ++允许一些额外的选项:
struct Callback {
virtual void operator()(const char *) = 0;
};
void adder_function(Callback &cb) {
a = a + b;
cb("foo");
b = a + c;
}
int main() {
struct Cb : Callback {
void operator()(const char *arg) { printf("Foo %s\n", arg); }
} cb;
adder_function(cb);
}
如果你有C ++ 11 std::function
,可以是编译器中的C ++ 0x / C ++ 11支持,C ++ TR1(作为std::tr1::function
)或者来自Boost({{1}你可以避免手动声明虚拟基类。
boost::function
避免虚拟基类的其他方法,这次也是虚拟调度(代码是编译两次的代码)是(适用于C ++ 98):
#include <functional>
void adder_function(std::function<void (const char *)> cb) {
a = a + b;
cb("foo");
b = a + c;
}
void callback1(const char *arg) { puts(arg); }
int main() {
struct { // You can have local structures, even with methods, but not local functions
void operator()(const char *arg) { printf("Foo %s\n", arg); }
} callback2;
adder_function(&callback1); // std::function should accept either function or functor
adder_function(callback2);
}
最后如果你在编译器中有C ++ 11支持(无法在库中执行此操作,这是新语法),您可以将最后两个与新的lambda语法结合使用:
template <typename Callback>
void adder_function(Callback cb) {
a = a + b;
cb("foo");
b = a + c;
}
void callback1(const char *arg) { puts(arg); }
int main() {
struct Callback2 { // Anonymous types can't be used in templates before C++11.
void operator()(const char *arg) { printf("Foo %s\n", arg); }
} callback2;
adder_function(&callback1); // template also accepts either function pointer or functor
adder_function(callback2);
}
答案 8 :(得分:0)
如果你不介意,我会重构它以打破责任。我将解析与程序流分开,该程序流决定在解析输入时要做什么。在封闭函数中,您将只调用帮助程序,并根据返回(或异常)确定要显示的错误,是否遇到错误,或者要设置的变量。这将从解析网表中删除重复(解析对于输入和输出完全相同,唯一的变化是要显示的错误消息以及是否设置输入/输出标志。标志的设置可以在外部完成,如果你的解析器返回一系列名称,那么外部代码可以构造节点并根据阶段设置标志。你的过程。