William 35 25000 Kishore 41 35000 Wallace 37 20000 Bruce 39 15000
William 35 28000 Kishore 41 35000 Wallace 37 23000 Bruce 39 18000
#include <stdlib.h>
#include <stdio.h>
typedef char String[32];
typedef FILE* File;
typedef struct _Employee {
String name;
int age;
int salary;
struct _Employee *next;
} *Employee;
typedef void (*Callback)(Employee);
/* High Order Functions */
void foreach(Employee e, Callback fn) {
Employee p;
while (p = e) {
e = e->next; /* Avoid *next be changed in fn */
fn(p);
}
}
void with_open_file(String filename, String mode, Callback fn, Employee e) {
File file = freopen(filename, mode, (mode[0] == 'r'? stdin: stdout));
if (file == NULL) {
fprintf(stderr, "Cannot open %s with %s mode.\n", filename, mode);
exit(EXIT_FAILURE);
}
fn(e);
fclose(file);
}
/* Destructor */
static void employee_free_node(Employee e) {
if (e != NULL) {
free(e);
}
}
void employee_free(Employee e) {
foreach(e, employee_free_node);
}
/* Input */
static void employee_read_node(Employee node) {
Employee e = NULL, *head = (Employee*) node;
e = *head = (Employee)calloc(1, sizeof(struct _Employee));
if (e != NULL && scanf("%s%d%d", e->name, &e->age, &e->salary) != 3) {
employee_free(e);
*head = NULL;
}
}
void employee_read(Employee list) {
Employee e = NULL, *head = (Employee*) list, tail = NULL;
*head = NULL;
while (employee_read_node((Employee)&e), e) {
if (*head != NULL) {
tail->next = e;
tail = e;
} else {
*head = tail = e;
}
}
}
/* Output */
static void employee_print_node(Employee e) {
printf("%s %d %d\n", e->name, e->age, e->salary);
}
void employee_print(Employee e) {
foreach(e, employee_print_node);
}
/* Business Logic */
static void employee_adjust_salary_node(Employee e) {
if (e->salary < 30000) {
e->salary += 3000;
}
}
void employee_adjust_salary(Employee e) {
foreach(e, employee_adjust_salary_node);
}
int main(void) {
Employee e = NULL;
with_open_file("work.txt", "r", employee_read, (Employee)&e);
employee_print(e);
employee_adjust_salary(e);
employee_print(e);
with_open_file("work.txt", "w", employee_print, e);
employee_free(e);
return EXIT_SUCCESS;
}
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
楼主这是节点遍历时,通过函数指针动态加载节点处理函数的设计方法。这个几年前写过,后来不这么写了。主要有以下几个问题。
1、每个节点被访问时,操作可能不一样,通用的函数指针的入口参数,要么可变参,要么多套,入口指针,都是很繁琐的事情,把代码逻辑结构搞的会更复杂。
2、操作函数和操作对象没有绑定,这个在规模开发时,很容易引起混乱。这样设计的代码,我自己到后面都觉得混乱,更别说基于我的架子让别人开发,楼主你的例子不够复杂可能感觉不到。
3、上面两个问题,也导致,代码复用率不高。
现在我的设计思想,如果是基础的数据结构,如同你这个例子中就是个线形表,我都全部独立成模版,在头文件中。
特定数据的处理不会和处理方法绑定,而是调用不同通用模块来处理,这样是尽可能的让数据和处理松耦合。而关联数据再怎么关联,处理时,也是一类整体处理的,同时一批数据再怎么复合,总可以拆成不同大部分串联处理(例如,读取、处理、写出,通过增加cache的方式可以分批分步骤完成,而不是读、处理、写 、一个完整操作周期,仅针对一个单元)。所以这类数据的整体处理落在通用模块里,通过数据和处理的紧耦合的提升效率。 ###### 另外,补充说一下,楼主的函数式风格,和我的函数式风格理解相差颇大。我的理解如下,所谓函数式风格,是将一批数据的若干处理,分解为正交串接的多个子步骤,每个步骤都是对整体数据的某个操作的实现。楼主的方案实质是对一个处理,可以挂接不同的操作方法。
我的理解函数式的风格在于每个独立模块处理极少的有逻辑关联的操作,可以看作针对一个数据池的原子操作。依次将数据池的数据灌入不同的独立模块,实现数据处理。当然差异的模块调用顺序和不同处理模块的组合,可以有不同的效果。
但无论如何,都是函数与数据松耦合的设计。这个和面向对象是反过来的。 ######相互嵌套耦合,牵一发动全身######楼主的代码有很浓重的其他语言的味道######楼主文章不错,我看现在的C模块基本就是你所说的面向对象风格,其实就是用数据结构组织起来。######
| 最高层:使用API的程序 | main |
| 基于Employee的接口实现的高级操作 | employee_print, employee_adjust_salary |
| 基于最底层的C,对象Employee的最基础的操作,包括读入、释放、遍历等 | employee_read, employee_free, foreach, with_open_file |
| C语言本身提供的最底层的工具 | struct Empoloyee, for, free, calloc... |
| 最高层:使用API的程序 | main |
| 基于Employee的接口实现的高级操作 | employee_print, employee_adjust_salary |
| 基于最底层的C,对象Employee的最基础的操作,包括读入、释放、遍历等 | employee_read, employee_free, foreach, with_open_file |
| C语言本身提供的最底层的工具 | struct Empoloyee, for, free, calloc... |