转自 http://blog.csdn.net/xkarl/article/details/6340180

Log4C,Log4CPlus/Log4cpp,Log4j,Log4Net,Log4Perl,Log4PHP,Log4PLSQL,Log4LS,Log4py,Log4r,qmmslog,JDK1.4's util.logging framework是常用的LOG调试库,log4**的架构都类似

       虽然C不是面向对象语言,但是log4c的实现完全是面向对象思想,和log4j的实现方式几乎雷同

       Log4c需要设置的,也就是面向用户的,接口有

category:log的日志模块

Appender:log输出方式stream,mem,syslog等

Layout:log打印方式,基本的,详细的(比如详细时间等)

1、  Factory Method工厂方法的管理

       这里的SD(Service Design)就相当于一个N个工厂集合(log4c_category_factory和log4c_appender_factory和log4c_layout_factory是单态的工厂,通过sd_factory_xx来做管理)

       不要理解为polymorphism,只不过提供一个Service Design的统一API而已,根据实际需要是可以分离开的,

factory.h :

struct __sd_factory {

char* fac_name;

const sd_factory_ops_t* fac_ops;

sd_hash_t* fac_hash;

};

typedef struct __sd_factory sd_factory_t;

extern sd_factory_t* sd_factory_new(const char* a_name, const sd_factory_ops_t* a_ops);

extern voidsd_factory_delete(sd_factory_t* a_this);
extern void*sd_factory_get(sd_factory_t* a_this, const char* a_name);
extern voidsd_factory_destroy(sd_factory_t* a_this, void* a_pr);
extern voidsd_factory_print(const sd_factory_t* a_this, FILE* a_stream);
extern intsd_factory_list(const sd_factory_t* a_this, void** a_items,
int a_nitems);

2、  Factory Method工厂方法

       因为面向用户配置选项,appender和layout在用户看来接口都一样,创建和删除以及打印,拥有共同的操作,fac_new/fac_delete/fac_print

factory.h :

struct __sd_factory {

char* fac_name;

const sd_factory_ops_t* fac_ops;

sd_hash_t* fac_hash;

};

typedef struct __sd_factory sd_factory_t;

struct __sd_factory_ops

{

void* (*fac_new)     (const char*);

void  (*fac_delete)         (void*);

void  (*fac_print)   (void*, FILE*);

};

typedef struct __sd_factory_opssd_factory_ops_t;

       fac_name用来区分appender/layout,fac_hash用来储存,方便查
找,如果更多的接口的话都无妨(个人喜好用链表代替hash),当不同模块Appender.c/
Layout.c都预先添加到hash中,如果还有ABC模块/XYZ模块,照样预先添加到HASH,模块非常的独立

Appender.c :

static const sd_factory_ops_tlog4c_appender_factory_ops = {

(void*) log4c_appender_new,

(void*) log4c_appender_delete,

(void*) log4c_appender_print,

};

Layout.c :

static const sd_factory_ops_tlog4c_layout_factory_ops = {

(void*)log4c_layout_new,

(void*)log4c_layout_delete,

(void*)log4c_layout_print,

};

       添加子fac到HASH后,在用户接口层,根据fac_name,通过
sd_hash_lookup查找HASH,找到fac_ops,有了fac_ops,就有了fac_new/fac_delete
/fac_print,这个时候的地址是相应的函数指针----或者appender或者layout或者ABC或者XYZ

3、  Descriptor多态

       在log4c_appender_new具体函数中,又面临一个问题是,appender有不同的输出方式:stream,mem,syslog等,

appender.h :

typedef struct log4c_appender_type {

const char*       name;

int (*open)          (log4c_appender_t*);

int (*append) (log4c_appender_t*, const log4c_logging_event_t*);

int (*close)  (log4c_appender_t*);

} log4c_appender_type_t;

Appender.c :

static const log4c_appender_type_t * constappender_types[] = {

&log4c_appender_type_stream,

&log4c_appender_type_stream2,

&log4c_appender_type_mmap,

&log4c_appender_type_syslog,

&log4c_appender_type_rollingfile

};

static size_t nappender_types =sizeof(appender_types) / sizeof(appender_types[0]);

       这里用一个指针数组,毕竟输出类型是有限的

Appender_type_stream.c :

const log4c_appender_type_tlog4c_appender_type_stream = {

"stream",

stream_open,

stream_append,

stream_close,

};

Appender_type_mmap.c :

const log4c_appender_type_tlog4c_appender_type_mmap = {

"mmap",

mmap_open,

mmap_append,

mmap_close,

};

Appender_type_syslog.c :

const log4c_appender_type_tlog4c_appender_type_syslog = {

"syslog",

syslog_open,

syslog_append,

syslog_close,

};

       同样操作,将上面不同类型添加到HASH,上面是指针数组的成员,在
log4c_appender_type_get运行时候,根据appender_name,通过通过sd_hash_lookup查找HASH,找到
open/ append/ close的指针,也就是具体的函数指针,或者stream_open/ mmap_open/ syslog_open等

       在log4c_layout_new具体函数中,有不同的输出方式:data,time等,同样是一个多态的实现

4、  实际应用例子

int main()
{
...
root = log4c_category_get("root");
sub1 = log4c_category_get("sub1");

layout1   = log4c_layout_get("layout1");
log4c_appender_t* appender1 = log4c_appender_get("appender1");

log4c_layout_set_type(layout1, &log4c_layout_type_basic_r);

log4c_appender_set_layout(appender1, layout1);
log4c_appender_set_udata(appender1,  stdout);

log4c_category_set_appender(sub1, appender1);
log4c_category_set_priority(sub1, LOG4C_PRIORITY_ERROR);
...
}

       factory打印结果,udata是stderr、stdout等:
factory[log4c_category_factory]:
{ name:'root' priority:NOTSET additive:1 appender:'(nil)' parent:'(nil)' }
{ name:'sub1' priority:ERROR additive:1 appender:'appender1' parent:'root' }

factory[log4c_appender_factory]:
{ name:'stderr' type:'stream' layout:'basic' isopen:0 udata:10311428}
{ name:'stdout' type:'stream' layout:'basic' isopen:0 udata:10311408}
{ name:'appender1' type:'stream' layout:'layout1' isopen:0 udata:10311428}

factory[log4c_layout_factory]:
{ name:'layout1' type:'basic_r' udata:00000000 }
{ name:'basic' type:'basic' udata:00000000 }
{ name:'dated' type:'dated' udata:00000000 }
       (1)可以看到有几个默认设置的,这是因为代码中默认配置了几项:
/* build default appenders */
log4c_appender_set_udata(log4c_appender_get("stderr"), stderr);
log4c_appender_set_udata(log4c_appender_get("stdout"), stdout);

/* build default layouts */
log4c_layout_set_type(log4c_layout_get("dated"), &log4c_layout_type_dated);
log4c_layout_set_type(log4c_layout_get("basic"), &log4c_layout_type_basic);

       (2)3次fac_ops

log4c_category_factory = sd_factory_new("log4c_category_factory",&log4c_category_factory_ops);
log4c_appender_factory = sd_factory_new("log4c_appender_factory",&log4c_appender_factory_ops);
log4c_layout_factory = sd_factory_new("log4c_layout_factory",&log4c_layout_factory_ops);  
(后两个new的时候是默认的类型log4c_appender_type_stream log4c_layout_type_basic)
(log4c_appender_factory->fac_hash,log4c_layout_factory->fac_hash类似LIST_HEAD的概念)
(a_name对应就是log4c_***_type_t中的name)

       (3)如果配置在log4crc:
<category name="mycat" priority="debug" appender="stdout" />     
<appender name="stdout" type="stream" layout="basic"/>    
<layout name="basic" type="basic"/>
3次fac_ops、3次sd_factory_get,不同的是,会增加
log4c_category_set_priority
log4c_appender_set_type
log4c_layout_set_type
来配置类型

5、  小结

       其实Factory_ops和Discriptor都没有必要HASH或者链表,毕竟这里分类有限,特别是对于log4c的代码而言,Discriptor直接数组中循环判断即可,HASH完全是多余

       反倒是Factory_ops在分类很多的情况下,采用HASH或者链表,因为
Factory_ops面向的层次更高,实际项目中分工是每个人几个子fac,采用数组耦合性太强,采用HASH或者链表,只要新加一个fac_ops,
只需添加到HASH或者链表,到时候查找即可

       在fac_ops具体实现中,name不同,就必须新开一块内存,所以必须采用HASH或者链表,比如log4c_appender_factory->fac_hash,log4c_layout_factory->fac_has就是HASH的HEAD

log4c面向对象设计 (转)的更多相关文章

  1. Java程序员应该了解的10个面向对象设计原则

    面向对象设计原则: 是OOPS(Object-Oriented Programming System,面向对象的程序设计系统)编程的核心,但大多数Java程序员追逐像Singleton.Decorat ...

  2. UML类图与面向对象设计原则

    1. 引言     从大一开始学习编程,到如今也已经有两年了.从最初学习的Html,Js,JaveSe,再到JavaEE,Android,自己也能写一些玩具.学习过程中也无意识的了解了一些所谓的设计模 ...

  3. 面向对象设计之SRP(单一职责)原则

    SRP设计原则面向对象类设计的第一个原则,最优先考虑的因素 一个类应该有且仅有一个职责.所谓一个类的职责是指引起该类变化的原因,如果一个类具有一个以上的职责,那么就会有多个不同的原因 引起该类变化,其 ...

  4. day24:面向对象设计与面向对象编程、类和对象

    一.三大编程范式: 面向过程: 面向函数: 面向对象: 二.程序的进化论: 1.编程最开始就是无组织无结构,从简单控制流中按步写指令 2.从上述的指令中提取重复的代码块或逻辑,组织到一起(比方说,你定 ...

  5. 【转】面向对象设计的SOLID原则

    S.O.L.I.D是面向对象设计和编程(OOD&OOP)中几个重要编码原则(Programming Priciple)的首字母缩写. SRP The Single Responsibility ...

  6. 6. javacript高级程序设计-面向对象设计

    1. 面向对象设计 1.1 理解对象 1.1.1 属性类型 (1). 数据属性:相当于对象的字段,包含一个数据值的位置,在这个位置可以读取和写入值.数据属性中有4个描述其行为的特性: l [[Conf ...

  7. 【OOAD】面向对象设计原则概述

    软件的可维护性和可复用性 知名软件大师Robert C.Martin认为一个可维护性(Maintainability) 较低的软件设计,通常由于如下4个原因造成: 过于僵硬(Rigidity)  ...

  8. 面向对象设计的SOLID原则

    S.O.L.I.D是面向对象设计和编程(OOD&OOP)中几个重要编码原则(Programming Priciple)的首字母缩写. SRP The Single Responsibility ...

  9. 面向对象设计SOLID五大原则

    转载自:码农社区,http://w3croom.com/read.php?tid-4522.html 今天我给大家带来的是面向对象设计SOLID五大原则的经典解说.       我们知道,面向对象对于 ...

随机推荐

  1. jQuery Ajax 参数解析

    简单的例子: $.ajax({ type:"post", data:{a:acon,b:bcon} , url:"ajax.php", async:false ...

  2. 查看iOS Crash logs

    当应用在设备中运行发生崩溃,iOS将记录这些错误日志并且创建了崩溃报告(Crash Report).崩溃报告中包含了iOS的版本.日期.异常类型.堆栈跟踪以及其他信息. ① 在Xcode中查看崩溃报告 ...

  3. 使用神经网络识别手写数字Using neural nets to recognize handwritten digits

    The human visual system is one of the wonders of the world. Consider the following sequence of handw ...

  4. windows 服务器不能使用剪贴板解决办法

    您可以在系统资源中先结束rdpclip.exe进程,然后重新打开c:\windows\system32\rdpclip.exe即可

  5. Spark2-对于Null/Nan的处理

    一.几种查找空值的方法 1.Column方法 column.isNull/column.isNotNull/column.isNaN 2.类sql方法 二.na方法 2.1 na.drop方法 2.1 ...

  6. cglib Demo

    转载自:http://huihai.iteye.com/blog/858524 http://www.cnblogs.com/shijiaqi1066/p/3429691.html

  7. 记一次vue2路由参数传递this指针问题

    需要船体一个data()内的对象到另一个页面. <player-card v-for="(note, key) in sortedtNodes" :imgurl=" ...

  8. (六)SSO之CAS框架扩展 改动CAS源代码实现与ESS动态password验证对接

    题记: 偶尔的偶尔我们会听到这个站点的数据泄露了,那个站点的用户数据泄露了.让用户又一次改动登录password,所以,对于用户数据安全性越发的引起我们的重视了,尤其是一些保密性要求高的站点.更须要添 ...

  9. Maven中的SNAPSHOT版本和正式版本理解

    Maven中建立的依赖管理方式基本已成为Java语言依赖管理的事实标准,Maven的替代者Gradle也基本沿用了Maven的依赖管理机制.在Maven依赖管理中,唯一标识一个依赖项是由该依赖项的三个 ...

  10. TestNG系列之三:TestNG忽略测试

    有时,我们的代码是没有准备好,如果测试用例写入到测试方法/代码将无法运行,在这种情况下, @Test(enabled = false)有助于禁用此测试案例.