转自 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. Ubuntu下轻松安装virtualbox

    转自:http://blog.csdn.net/flm2003/article/details/8168628 以下假设你的Ubuntu系统版本为11.10的64位版本,进行如下操作: 1.到http ...

  2. 修改centos7/osx的MAC地址

    change MAC Address in CentOS 7: nano /etc/sysconfig/network-scripts/ifcfg-ens160 systemctl restart n ...

  3. SQL Compare 10.4.8.87 Edition 数据库比较工具 完全破解+使用教程

    一.使用教程 SQL Compare是编程人员常用的比较两个数据库之间差异的工具.可以用来比较数据库里面的对象.比如存储过程,数据库中的数据,表的结构. 下面我就简单介绍一下如何使用 1.选择要比较的 ...

  4. python wheel 包命名规则和 abi 兼容

    wheel 包的命名规定 wheel 包的命名格式为 {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform ...

  5. jTemplates模板学习笔记

    1.jTemplates工作方式   1)setTemplateElement:指定可处理的模板对象 2)processTemplate:对模板化的对象进行数据处理 2.语法解析   1)jTempl ...

  6. Java笔记12:Java对象排序

    代码: import java.util.Arrays; import java.util.Comparator; class Person { private String name; privat ...

  7. 【实践】用 js 封装java shuffle函数(打乱数组下标方法)

    此方法返回的会是一个全新的数组 所以并不会像java里的shuffle函数一样返回一个引用一样的数组 思路如下: 1.新建一个函数传入需要打乱下标的数组 2.获取数组的长度 3.新建一个用来保存并且返 ...

  8. RocketMQ里的一个获取时间的工具类SystemClock

    看rocketmq源码的时候发现他们还给时钟封装里一下. /** * Licensed to the Apache Software Foundation (ASF) under one or mor ...

  9. 用户手册是Yasm汇编

    本文档的用户手册是Yasm汇编. 它是介绍和通用所有Yasm用户参考. 英文的参考:http://www.cnblogs.com/coryxie/p/3959888.html 1 .介绍 Yasm b ...

  10. CardLayout使用

    相对于BoxLayout,GridBugLayut等常用的Swing layout,CardLayout是特殊的,前者是一个容器内布置组件,而后者是在一个容器内放置很多页面(但一个时间只用显示一个). ...