发现老庄的连载方法很好.又能吸引眼球又能好整以暇.于是从善如流.
这几天在完善我的neptune系统和jaskell语言。顺手发现了一个logging的需求。如获至宝阿。
为什么呢?不是因为这个需求多么难,或者我的解决方法多么巧妙,而是因为,这个例子足够简单,直观,要说明它,背景知识几乎不大需要,三两句话大家就明白需要达到什么效果。这种例子可不是随便就想得到的。
而同时,它又对实现提出了一定程度的灵活性要求,正好方便我展示我叫做“面向组合子”的程序设计方法。
说到这里,不禁又有点沮丧,我也挺想象别人那样,先高举高打,玄之又玄,弄些哲学思辨,什么佛法呀,道德经阿,西游记亚,以及各位西方先哲的亟语,甚至量子力学的悖论。这样才能吸引眼球,增加人气呀。
可是,等而下之的工匠气作祟,说着说着就要拐到具体例子上去了。不争气呀。
算了,不想那么多了。论道不是俺这种俗人所擅长的,还是鼓捣“器”吧。
大致的背景是这样:
我的neptune是一个build system,在build的过程中会产生很多log信息。这些信息分为不同的重要级别。
说到这里,肯定有人已经按奈不住:用Log4j!
先不要急,我们这里不是要告诉你怎么处理你得程序中的logging需求,而是要通过这样一个容易理解的例子来说明以下“面向组合子”的编程方法。所以,这里让我们先假设我们不知道什么log4j。什么是log4j呀?
当然,大致的思路总归差不多的。因为我的neptune系统只需要一个logging的工具,而不关心这个logging工具是什么,这就是一个perfect的依赖注射的场合。
先定义接口Logger,然后从构造函数传递近来一个Logger实例,接着就直接调用Logger就是了。
public interface Logger{
void print(int level, String msg);;
void println(int level, String msg);;
void logException(Throwable e);;
}
print用来输出信息,但是不折行,println可以折行。
logException用来直接纪录异常。这样,对异常是直接printStackTrace,还是println(e.getMessage())就是由具体的Logger实现来决定,我的neptune只需要把遇到的异常报告给Logger就是了。
好。接下来我吭哧吭哧地把neptune完成了,剩下的就是从哪里找一个Logger实现了。
最简单的Logger实现自然就是直接往屏幕上打印了:
class SimpleLogger implements Logger{
public void print(int lvl, String msg);{
System.out.print(msg);;
}
public void println(int lvl, String msg);{
System.out.println(msg);;
}
public void printException(Throwable e);{
e.printStackTrace();;
}
}
直接把这个SimpleLogger注射进我的neptune,整个系统就可以工作了。
no big deal,对么?
好了,下面我们开始真正实现完整的logging系统了。经过分析,我们大致有以下的需要:
[list]1。logger可以把信息打印到log文件中。
2。不同的重要程度的信息也许可以打印到不同的文件中?象websphere,有error.log, info.log等。
如果这样,那么什么重要程度的信息进入error.log,什么进入warning.log,什么进入info.log也需要决定。
3。也许可以象ant一样把所有的信息都打印到一个文件中。
4。每条logging信息是否要同时打印当前的系统时间?也是一个需要抉择的问题。
5。不仅仅是log文件,我们还希望能够在标准错误输出上直接看见错误,普通的信息可以打印到log文件中,对错误信息,我们希望log文件和标准输出上都有。
6。标准输出上的东西只要通知我们出错了就行,大概不需要详细的stack trace,所以exception stack trace可以打印到文件中,而屏幕上有个简短的exception的message就够了。
7。warning似乎也应该输出到屏幕上。
8。不管文件里面是否要打印当前系统时间,屏幕上应该可以选择不要打印时间。
9。客户应该可以通过命令行来决定log文件的名字。
10。客户可以通过命令行来决定log的细节程度,比如,我们只关心info一样级别的信息,至于debug, verbose的信息,对不起,不要打印。
11。neptune生成的是一些Command对象,这些对象运行的时候如果出现exception,这些exception会带有execution trace,这个execution trace可以告诉我们每个调用栈上的Command对象在原始的neptune文件中的位置(行号)。
这种exception叫做NeptuneException,它有一个printExecutionTrace(PrintWriter)的方法来打印execution trace。
所以,对应NeptuneException,我们就不仅仅是printStackTrace()了,而是要在printStackTrace()之前调用printExecutionTrace()。
12。neptune使用的是jaskell语言,如果jaskell脚本运行失败,一个EvaluationException会被抛出,这个类有一个printEvaluationTrace(PrintWriter)的方法来打印evaluation trace,这个trace用来告诉我们每个jaskell的表达式在脚本文件中的位置。
所以,对应EvaluationException,我们要在printStackTrace()之前,调用printEvaluationTrace()。
13。execution trace和evaluation trace应该被打印到屏幕上和log文件两个地方。
14。因为printExecutionTrace()和printEvaluationTrace()本身已经打印了这个异常的getMessage(),所以,对这两种异常,我们就不再象对待其它种类的异常那样在屏幕上打印getMessage()了,以免重复。
15。也许还有一些暂时没有想到的需求, 比如不是写入log文件,而是画个图之类的变态要求。[/list:u]
大致上,我目前遇到的需求也就是这些了。
好了,允许我卖个关子,下回分解的时候再说怎么用“面向组合子”和依赖注射的方法来解决这个问题吧。
在本节结束之前,我稍微提一下“面向组合子”的来历。
组合子,英文叫combinator,是函数式编程里面的重要思想。如果说OO是归纳法(分析归纳需求,然后根据需求分解问题,解决问题),那么“面向组合子”就是“演绎法”。通过定义最基本的原子操作,定义基本的组合规则,然后把这些原子以各种方法组合起来。我最近一段时间做的东西,jaskell不用说了,函数式语言。yan, neptune, jparsec全是用面向组合子的思想开发的。
OO就像是猜谜,给你一个苹果,然后问你:这个苹果是怎么得到的呢?然后你分析一番,说:我认为这个苹果是由分子组成的,这些分子如此这般排列,然后分子又由原子组成,如此这般排列...
而CO(面向组合子),就等于是说:这有H, C, O三种原子,强弱两种作用力,你来看看能做点什么出来吧,然后你就像搭积木一样,把这三种原子,两种作用力搭建出这大千世界,什么毛毛虫,狗熊,周星星,不小心,一下就做出了一个苹果。
OO的关键是需求。
所谓"refactor",不过也是强调需求,让你不要自作聪明地瞎假设需求而复杂化设计。时刻着眼于当前的需求。这样,一旦需求变更,所浪费的力气可以保证最小,而且,船小才好调头嘛。
如果需求分析的不好,一切就歇菜了,虽然因为一些比如ioc之类的设计方法能让你不至于推到重来,但是需求仍然是重中之重。
那些什么上下文没有,上来就说“怎么用OO来做一个人骑车呀?”,“是人.骑(车)呀?还是车.被骑(人)?”纯粹是没头没脑地瞎掰。
而CO的关键则是组合子和组合规则的设计。这些组合方法必须非常精巧,尽量正交。组合子的设计既要简单(越简单才越容易被组合),还要完整。
比如说,对整数这个组合子,我们有+-*等组合方法,这样只要有了0,1这两个组合子,我们就可以构造出整个整数世界。
可是,精巧的组合子设计也不是那么容易的。需要有一点点数学的感觉和严密的逻辑思维基础。
有人说,上帝是用OO设计的世界,可要我是上帝,我宁可用CO。
设计几个简单的基本粒子,几个简单的相互作用力,然后让这些东西自己组合,随意发展,不是比事必躬亲,先想透彻了自己想让世界是什么样子,然后一张一张图纸地具体设计,一个一个人地造,
“撒旦,你去干坏事,往死了整这帮贱人!”
“天使,你去干好事,打个巴掌再给他们点甜枣吃。”
“儿子,你下去混混,看丫敢不敢钉死你!”
来的容易美妙?
哈。终于形而上起来了,爽!
分享到:
相关推荐
C++面向对象程序设计教程(第3版) 目录: 第1章 面向对象程序设计概述,第2章 C++概述,第3章 类和对象,第4章 派生类与继承,第5章 多态性,第6章 模板与异常处理,第7章 C++的流类库...第8章 面向对象程序设计方法与实例.
《Java与UML面向对象程序设计》强调理论和设计相结合,重视对软件开发方法学有指导作用的重要概念。《Java与UML面向对象程序设计》可作为高等学校计算机科学系及软件学院高年级学生和研究生的教科书,也可作为从事...
《C++ 面向对象程序设计》是周靖翻译的第七版教材,该书深入浅出地介绍了C++这门强大的编程语言,特别强调了面向对象编程的概念和实践。面向对象编程(Object-Oriented Programming,OOP)是C++的核心特性,它通过类...
面向对象编程(Object-Oriented Programming, OOP)是一种编程范式,它以对象作为程序设计的基本单元,强调数据和操作数据的方法紧密结合。本教程第三版在前两版的基础上进行了更新和完善,更适合当前的编程环境和...
### 综上所述,Abaqus用户子程序二次开发官方PPT教程中涵盖了从基本概念、编程技巧、特定子程序的接口使用,到实际案例分析的全方位知识。通过学习本教程,用户可以有效地进行ABAQUS的二次开发,以满足特定工程问题...
本资源包容金旭亮《C#面向对象程序设计》教案的最后3讲:7 对象集合与对象组合;8 泛型编程;9 对象间的协作与信息交换。包容相关PDF文档及VS2010示例源码。请关注金旭亮博客以获取更多技术资源:...
第五、六章叙述循述循环、分支、子程序等基本程序结构以及程序设计的基本方法和技术;第七章为宏汇编技术;第八章说明以中断为主的输入/输出程序设计方法;第九章介绍BIOS和DOS系统功能调用的使用方法;第十~十二章...
《基于微信小程序点餐系统的设计与实现》 随着信息技术的快速发展,互联网已深入人们生活的各个领域,其中,餐饮行业的数字化转型尤为明显。微信小程序作为移动应用的一种轻量化形式,为餐饮业提供了便捷的线上点餐...
基础部分主要以8086/8088微处理器和DOS操作系统为学习平台,介绍汇编语言基础知识、寻址方式、指令系统和程序设计方法。提高部分则是针对80386微处理器及其保护模式下的编程技术和细节。最后,上机实验指导部分为...
《程序设计语言 实践之路 第3版》是一本深度探讨编程语言原理与实践的书籍,由Michael L. Scott撰写。本书旨在帮助读者理解各种编程语言的设计选择,以及这些选择如何影响程序的构造、效率和可维护性。通过阅读这...
本文档是一篇关于基于微信小程序的点餐系统设计与实现的毕业论文,旨在利用微信小程序这一日益普及的技术,优化餐厅点餐流程,提供便捷的在线点餐服务。论文详细介绍了系统的开发背景、技术选型、需求分析、系统设计...
Visual C# 2010程序设计教程》详细介绍了Visual C# 2010程序设计的基础知识、基本方法和应用技巧,共分14章,主要内容包括.NET平台与Visual Studio 2010开发环境、C#语言基础及面向对象程序设计、C#程序设计、C# Web...
《C#程序设计及应用教程(第3版)》是一本深入浅出的C#学习教材,由马骏主编,其特色在于结合丰富的实例和课后习题来帮助读者掌握C#编程的基础与进阶技巧。这个压缩包包含了该书各章节的习题解答,覆盖了从基础到...
1. 封装:封装是面向对象编程的核心原则之一,它将数据和操作数据的方法绑定在一起,隐藏内部实现细节,只对外提供公共接口。通过访问修饰符(如public、private、protected),我们可以控制对类成员的访问权限,...
综上所述,本文件提供的信息重点在于介绍一本名为“CCF中学生计算机程序设计-入门篇”的电子资源,强调其作为备课准备的价值,并提供了与之相关的出版和联络信息。同时也突出了纸质书籍与电子版在学习效果上的差异,...
《钱能C++程序设计教程第二版》是一本广受欢迎的C++学习教材,其课后答案对于初学者和进阶者来说都是极其宝贵的资源。C++是一种强大的、通用的编程语言,它融合了面向过程和面向对象的编程思想,是软件开发领域的...
刘金琨滑《滑模变结构控制MATLAB仿真》第3版 基本理论与设计方法pdf+仿真程序 滑模变结构控制本质上是一类特殊的非线性控制,其非线性表现为控制的不连续性,这种控制策略与其它控制的不同之处在于系统的“结构”...
面向过程编程是早期软件开发的核心思想,起源于20世纪60年代,由E.W.Dijkstra提出的“结构化程序设计”思想。这种编程方式强调将问题分解为多个独立的模块,通过“自顶向下,逐步求精”的方法来设计程序。程序员首先...