2007年4月13日
#
---转自网络
运行cmd regedit msconfig提示找不到文件
作者: 笑嘻嘻
今天我同学的电脑,开始运行“cmd regedit msconfig” 这三个命令都不行 ,提示"找不到文件"。可是文件明明在阿。
直接运行system32目录下的cmd也不行,照样提示"找不到文件"。把cmd改名为cmd1就能够运行
我的处理过程:
开始我怀疑是中病毒了,是病毒程序在监听哪个程序标题为“cmd”,发现就结束。
首先用卡巴扫了一下启动项,没发现病毒。又用冰刃查了一下启动项,进程,都没问题。
想了想会不会中了rootkit 级的马儿,可用冰刃仔细看了看内核,没有显示红色的阿,刚才杀毒软件也没报,是的可能性就不怎么大了。
那会不会是这个文件遭病毒感染了,我最讨厌感染型的蠕虫病毒了。我从我自己的电脑上把才cmd.exe拷贝过来了,用软件比较了下(光看大小不行的),一样的。
Hash.zip (28.61 KB , 下载:6次)
----------------------------------------------------------------------------
文件: C:WINDOWSsystem32cmd.exe
大小: 470528 字节
文件版本: 5.1.2600.2180 (xpsp_sp2_rtm.040803-2158)
修改时间: 2005年12月15日, 8:00:00
MD5: 722A247ACB86960A708528120759266D
SHA1: A859B7173FB0B1786BE07B01F779725EDF9043E7
CRC32: 15544920
-----------------------------------------------------------------------------
后来经过询问前几天中过病毒,会不会是上次病毒修改了注册表什么地方,虽然病毒是被杀了,但是修改的地方仍然没有改过来的呢。结果证明,这个判断是正确的。
具体处理方法:
用冰刃的修改注册表,或者将windeows目录下的regedit.exe修改一下名字,比如叫regedit1.exe,修改注册表。
将HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionImage File Execution Options 里面的
cmd.exe
msconfig.exe
regedit.exe
regedit32.exe
删除就可以了。
典型的 映像劫持。
这只是处理病毒后遗症,具体的处理病毒的方法没有写,因为有很多病毒都会造成这种状况,具体病毒具体对待。
--转自
做共享软件是有利可图的,这是真的,1999年3月以前我还不信,可是经过一年多的
研究和实践下来,我已经每月能赚4万多美金了,比某些大公司总裁还多。但是,
我敢说,80%以上的共享软件作者并不成功,实际上,他们远远没有赚到他们本来可以
赚到的收入。
软件共享发行销售(先试后买)是一种市场营销手段,和其他所有市场营销手段一样,
是有学问的,要想通过软件共享发行获得成功,就必须掌握这些学问。
今天,我来贴上第一篇技术文章,收钱的办法
在几年以前,Internet还没有流行的时候,共享软件的作者只能靠从邮件中收到用户的支票和现金的方法来赚钱,而用户寄出支票后,还要等上一周或更多的时间得到来自作者的注册码。注意,当以下几种情况发生时,软件作者的生意就做不成了:
1)用户的支票本刚好用完,等他买回新支票本时,消费冲动已经没有了
2)用户的邮票刚好用完,他还不得不去一趟邮局买邮票,转念一想,这软件我也不是
非买不可,算了
3)用户无法忍受要等好多天才能拿到注册码
一句话,太不方便了
现在好了,有了Internet,有了电子商务,用户可以在最想买你的软件的一刹那间,迅速的用他的信用卡在网上买下你的软件,连后悔的时间都没有,共享软件发财的日子到来乐。
那么,如何在网上收取信用卡呢?
如果你拥有一个公司,在美国银行有信用卡商号帐户,又购买了银行的GATEWAY软件,在自己的网站上开发了信用卡收费系统当然很好,但对于广大共享软件作者来说,这很不现实.有简单的办法,就是找一家信用卡收款代理公司,让他们替你收款,你只要每个月等他们给你寄一张总额的支票(他们会提取一定比例的佣金)就行了.
这样的代理公司网站有:
WWW.QWERKS.COM 提成 15-20% (服务极好,是我的服务商)
WWW.Shareit.COM
WWW.REGNOW.COM
WWW.REGSOFT.COM
WWW.Kagi.com
对于咱们国内的共享软件作者,还要做的一件事就是去中国银行开个户头(北京中行的活期一本通就很好用),如果你打算让信用卡公司把钱电汇给你,你还要知道银行的英文名字,地址,帐户名,
帐号,转帐的SWIFT Code(可以从银行职员那里问到)
到信用卡代理公司的网站上开户非常简单,通常确认它们的一个在线协议,填入一些个人信息和产品信息,几分钟就OK了
这里面有一个值得注意的地方,就是,当用户付了款后,注册码怎么给的问题,你可以选择由你来给(每收到一份订单,他们会给你发一封email,包含用户资料和email),由你生成注册码email给用户,也可以把注册码生成代码给信用卡公司,让他们编到他们的系统里去,用户来了订单后自动发出注册码,也可以由你一次性生成几百个注册码给他们,他们每收到一份订单时用掉一个注册码。
我个人的意见是,这几个信用卡服务商信誉都非常好,一次给他们几百个注册码是最简单的办法,对服务商来说操作简单,对用户来说快,交完钱马上就得到注册码了
当你完成作者和产品在信用卡服务商那里的登记后,就会得到一个URL连接,你把这个连接加到你的主页上面,标上一个“Buy Now”,用户点这里就可以用信用卡付款了,当然,你也可以把这个连接做到你的软件界面里去,这样用户在试用你的软件时,随时想买都可以点击这个连接上网购买
具体实例可以参考我的网站和软件
http://www.zy2000.com
MP3 CD Maker
对于一些Internet软件,如断点续传的下载软件,还有另外一种赚钱方法,就是对用户免费,而在软件界面上登一个banner广告赚取广告费。最有名的广告代理商是
www.radiate.com
他的广告付费是每CPM 2-5美元,也就是说,如果一天里有10万个用户使用了你的软件一次的话,你就得到200-500美元。这家公司声称,著名的下载工具软件Gozilla!落户Radiate后,每月从Radiate那里赚到22万美元,我们著名的NetAnt是不是该赶快行动了?
我们也不反对用户用支票和现金购买软件,事实上,信用卡服务商都提供支票和现金收款业务,我们可以在网页中提供信用卡服务商的地址和服务热线电话,具体例子可以参考我的网页中 FAQ 一页的内容
1 .from
1.1单表查询
from eg.cat as cat.其中,cat只是一个别名,为了用其他子语句的时候书写简单
1.2多表查询
from eg.Cat,eg.Dog
from eg.Cat as cat,eg.Dog as dog
2 join相关
(inner) join
left (outer) join
right (outer) join
full join
HQL同样对SQL中的这些特性支持
下面插播一个小话题,关于上边的那些特性,我一直都没怎么用,今天既然说到这里,就想
把上边的几个特性的用法说一下,也算对自己的一个补充:
假设有两个表:部门、员工,下面列举一些数据:
员工(Employee):
ID Name DepNo
001 Jplateau 01
002 Jony 01
003 Camel 02
部门(Department):
ID Name
01 研发部
02 营销部
在Hibernate中我们操纵的都是对象,所以我们操纵的是部门类和员工类
1).(inner) join
select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name
as name2 from Employee as employee join Department as department on employee.DepNo=
department.ID (注意到条件语句我用on 没有用where)
那么执行结果是什么呢?
id1 name1 id2 name2
++++++++++++++++++++++++++++++++++++++
001 Jplateau 01 研发部
002 Jony 01 研发部
2).left (outer) join
select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name
as name2 from Employee as employee left join Department as department on employee.DepNo=
department.ID
那么执行结果又该是什么呢?
id1 name1 id2 name2
++++++++++++++++++++++++++++++++++++++
001 Jplateau 01 研发部
002 Jony 01 研发部
003 Camel null null
{就是说此时我要已第一个表的记录多少为准,第二个表中没有相应纪录的时候填充null}
3). right (outer) join
select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name
as name2 from Employee as employee right join Department as department on employee.DepNo=
department.ID
那么执行结果又该是什么呢?
id1 name1 id2 name2
++++++++++++++++++++++++++++++++++++++
001 Jplateau 01 研发部
002 Jony 01 研发部
null null 02 营销部
{就是说此时我要已第二个表的记录多少为准,第一个表中没有相应纪录的时候填充null}
3 大小写敏感
4。select语句
就是要确定你要从查询中返回哪些对象或者哪些对象的属性。写几个例子吧:
select employee form Employee as employee
select employee form Employee as employee where employee.Name like 'J%'
select employee.Name form Employee as employee where employee.Name like 'J%'
select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name
as name2 from Employee as employee right join Department as department on employee.DepNo=
department.ID
select elements(employee.Name) from Employee as employee
(不明白elements到底是做什么用的?望给于说明)
等等
5。数学函数
JDO目前好像还不支持此类特性。
avg(...), sum(...), min(...), max(...)
count(*)
count(...), count(distinct ...), count(all...)
其用法和SQL基本相同
select distinct employee.name from Employee as employee
select count(distinct employee.name),count(employee) from Employee as employee
6。polymorphism (暂时不知道如何解释?)
from com.test.Animal as animal
不光得到所有Animal得实例,而且可以得到所有Animal的子类(如果我们定义了一个子类Cat)
一个比较极端的例子
from java.lang.Object as o
可以得到所有持久类的实例
7。where语句
定义查询语句的条件,举几个例子吧:
from Employee as employee where employee.Name='Jplateau'
from Employee as employee where employee.Name like 'J%'
from Employee as employee where employee.Name like '%u'
在where语句中“=”不光可以比较对象的属性,也可以比较对象,如:
select animal from com.test.Animal as animal where animal.name=dog
8。表达式
在SQL语句中大部分的表达式在HQL中都可以使用:
mathematical operators +, -, *, /
binary comparison operators =, >=, <=, <>, !=, like
logical operations and, or, not
string concatenation ||
SQL scalar functions like upper() and lower()
Parentheses ( ) indicate grouping
in, between, is null
JDBC IN parameters ?
named parameters :name, :start_date, :x1 (这种应该是另一种"?"的变通解决方法)
SQL literals 'foo', 69, '1970-01-01 10:00:01.0'
Java public static final constants eg.Color.TABBY
其他不必解释了,在这里我只想对查询中的参数问题说明一下:
大家知道在SQL中进行传递参数进行查询的时候,我们通常用PreparedStatement,在语句中写一大堆的“?”,
在hql中也可以用这种方法,如:
List mates = sess.find(
"select employee.name from Employee as employee " +
"where employee.Name=? ",
name,
Hibernate.STRING
);
(说明:上面利用Session里的find方法,在hibernate的api Session中重载了很多find方法,它可以满足你多种形式的查询)
上边是一个参数的情形,这种情况下紧接着引入参数和定义参数的类型,当为多个参数,调用另一个find方法,它的后两个
参数都是数组的形式。
还有另外一种方法来解决上边的问题,JDO也有这样的方法,不过和hibernate的表现形式上有差别,但他们两个骨子里却是
一样的,如:
Query q = sess.createQuery("select employee.name from Employee as employee where employee.Name=:name");
q.setString("name", "Jplateau");
//当有多个参数的时候在此逐一定义
Iterator employees = q.iterate();
9。order 语句
和sql语句没什么差别,如:
select employee.name from Employee as employee where employee.Name like 'J%' order by employee.ID desc (或者asc)
10。group by 语句
同样和sql语句没什么差别,如:
select employee.name,employee.DepNo from Employee as employee group by employee.DepNo
select foo.id, avg( elements(foo.names) ), max( indices(foo.names) ) from eg.Foo foo group by foo.id
{Note: You may use the elements and indices constructs inside a select clause, even on databases with no subselects.}
谁帮我解释一下上边两句,谢过!
11。子查询
hibernate同样支持子查询,写几个例子:
from eg.Cat as fatcat where fatcat.weight > ( select avg(cat.weight) from eg.DomesticCat cat )
-转载
下面是作者对设计模式的理解并自以为所对应的实例
一 : 单例模式(Singleton)
账本类:1 单一实例 2 给多个对象共享 3 自己创建。网页计数器
二:策略模式(Strategy)
使用QQ泡MM时使用外挂 客户端 :ME 抽象类: 外挂 具体:策略(图片,笑话,名人名言)
图书销售算法(不同书本折扣的算法)
三:原型模式(Prototype)
复印技术: 1 不是同一个对象 2 属同类
短消息(转发) 1-n个MM
四:门面模式(Façade)
Facade典型应用就是数据库JDBC的应用和Session的应用
ME---àMM---à(father,mum,sister,brother)
五:备忘录模式(Memento)
备份系统时使用
GHOST
六 : 命令模式(Command)
MM(客户端)--àME(请求者)--à命令角色--à(具体命令)-à代理处(接收者)--àMM
上网 IE 输入 http地址 发送命令
七: 解释器(Interpreter)
编译原理之编译器
文言文注释:一段文言文,将它翻译成白话文
八:调停者模式(Mediator)
法院和原告,被告的关系
九:责任链模式(CHAIN OF RESPONSIBLEITY)
喝酒时通过成语接龙决定谁喝酒(马到成功-功不可没-没完没了)
十:工厂模式(Factory)
水果园—〉(葡萄园,苹果园)--〉(葡萄,苹果)(各自生产)
十一:抽象工厂模式(Abstract Factory)
女娲造人---〉(阴,阳)--〉(人,兽)----〉(男人,女人,公兽,母兽)(人和兽属于不同的产品类)
十二:建造模式(Builder)
汽车制造
十三:合成模式(Composite)
windows的目录树(文件系统)
十四:装饰模式(DECORATOR)
在visio中文件可以使用背景进行装饰
变废为宝
十五:设计模式之Adapter(适配器)
充电器(手机和220V电压)
jdbc-odbc桥
十六:桥梁模式(Bridge)
jdbc驱动程序
十七:代理模式(Proxy)
用代理服务器连接出网
销售代理(厂商)律师代理(客户)
foxmail
枪手
十八:享元模式(Flyweight)
字体的26个字母和各自的斜体等
十九:状态模式(State)
人心情不同时表现不同有不同的行为
编钟
登录login logout
二十:观察者模式(Observer)
公司邮件系统everyone@sina.com的应用。当公司员工向这个邮箱发邮件时会发给公司的每一个员工。如果设置了Outlook则会及时收到通知。
接收到短消息
二十一:模板方法模式(Template)
使用网页设计时使用的模板架构网页(骨架) 算法的各个逻辑系统
二十二:访问者模式(Visitor)
电脑销售系统: 访问者(自己)---〉电脑配置系统(主板,CPU,内存。。。。。。)
二十三:迭代子模式(Iterator)
查询数据库,返回结果集(map, list, set)
下面的参考文献是读书笔记的全部参考文献。这里不一定用到的。
参考文献:
http://blog.csdn.net/airhand/
http://blog.csdn.net/bloom121/
http://blog.csdn.net/laurecn/
http://blog.csdn.net/legendinfo/
http://www-128.ibm.com/developerworks/cn/java/l-struts1-1/
《Design Patterns》
《Java与模式》
《设计模式:可复用面向对象软件的基础》
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1227902
摘要: 事件源对象 event.srcElement.tagName event.srcElement.type
捕获释放 event.srcElement.setCapture(); event.srcElement.releaseCapture();
事件按键 event.keyCode event.shiftKey event.altKey event....
阅读全文
转自 IBM 刘武东,谢谢作者的辛勤劳动!
前言
Jive是一个开放的Java源代码项目。其目标是建设一个开放结构的,强壮的,易于扩展的基于JSP的论坛。在其设计目标的指导下,其结构设计得非常得好,融合了很多新的观念,比如Design Pattern,可更换的Skin,可插入Plug等等。详细解读其源代码对于理解这些新的设计上的概念是很有裨益的。如果你对Design Pattern和Java语言有一定的了解,但是还是会时常迷惑于其中的话,不妨研究研究Jive源代码,一定会对其中的很多概念有更深入的理解。这篇文章源于我的Jive源代码研究笔记,希望能够提纲挈领,带领大家进入到这个美好的世界。当然,如果没有时间仔细地看源代码的话,看看这篇文章,我想也是会有一些帮助的。
再开始之前,需要指出的是,Jive中对Design Pattern的应用,并没有拘礼与GOF书中所给出的实现方法,而是有许多变通的地方。一方面,我想是由于具体的实际需要,另一方面,我想这也是设计观念进化的结果吧。因而,这些变通的地方,将是我讲解的重点。
整体结构概叙
基于一个OO的设计原则:面向接口编程,而不是针对实现编程。Jive在设计的时候,把其大部分的基本对象都设计为接口或者抽象类。在Jive中,基本的接口有Forum,ForumMessage,ForumThread,Group,User,Authorization和Query。我们可以很容易的从这些接口的名字来知道他们的功用,下面的类图给出了这些类之间的一些静态关系:
图1:Jive整体关系
你可能会有疑问,为什么会都是接口呢?这是基于扩展性考虑的。在Jive给出的实现中,所有的这些接口,Forum,ForumMessage,User等等,都使用数据库来实现的,一条消息,或者一个用户对应于数据库中的一条消息Jive使用了DbForum,DbForumMessage,DbUser等类来实现这些接口,通过JDBC来操作数据库,使之作为论坛的底层支撑。
然而,有时候,或许我们并不想使用数据库,比如我们想只是使用文件系统来作为论坛的底层支撑,这时候,我们需要做的只是编码实现了Forum等等接口的诸如FileFroum,FileForumMessage等对象,然后嵌入Jive中即可,原有的任何代码都可以不用改变!!!这就是面向接口编程的威力了!
下面来看看具体的设计和编码。
AbstractFactory模式和可扩展性
如果要实现较好的可扩展性,AbstractFactory模式确实是一件利器。如上面所说,如果要创建的Forum接口的不同实现,而又不想更改代码的话,就需要用到抽象工厂了。再Jive中,AuthorizationFactory类是一个抽象类,用来创建Authorization对象。这是一个抽象工厂,可以通过不同的子类来创建不同的Authorization对象。这个工厂的实现方法是:
在AuthorizationFactory中使用一个private static变量factory,用来引用具体的抽象工厂的实例:
private static AuthorizationFactory factory = null;
用一个private static的String,来指明具体的抽象工厂的子类类名:
private static String className ="com.coolservlets.forum.database.DbAuthorizationFactory";
然后是用一个private static的loadAuthorizationFactory方法来给这个factory变量赋值,生成具体的抽象工厂类:
private static void loadAuthorizationFactory() {
if (factory == null) {
synchronized(className) {
if (factory == null) {
String classNameProp = PropertyManager.getProperty(
"AuthorizationFactory.className"
);
if (classNameProp != null) {
className = classNameProp;
}
try {
Class c = Class.forName(className);
factory = (AuthorizationFactory)c.newInstance();
}
catch (Exception e) {
System.err.println("Exception loading class: " + e);
e.printStackTrace();
}
}
}
}
}
|
在static的getAuthorization方法返回一个Authorization的过程中,先初始化工厂类factory变量,然后用factory的createAuthorization方法来创建:
public static Authorization getAuthorization(String username,
String password) throws UnauthorizedException
{
loadAuthorizationFactory();
return factory.createAuthorization(username, password);
}
|
不同的子类有不同的createAuthorization方法的实现。比如在DbAuthorizationFactory这个AuthorizationFactory的数据库实现子类中,createAuthorization方法是这样实现的:
public Authorization createAuthorization(String username, String password)
throws UnauthorizedException
{
if (username == null || password == null) {
throw new UnauthorizedException();
}
password = StringUtils.hash(password);
int userID = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(AUTHORIZE);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
if (!rs.next()) {
throw new UnauthorizedException();
}
userID = rs.getInt(1);
}
catch( SQLException sqle ) {
System.err.println("Exception in DbAuthorizationFactory:" + sqle);
sqle.printStackTrace();
throw new UnauthorizedException();
}
finally {
try { pstmt.close(); }
catch (Exception e) { e.printStackTrace(); }
try { con.close(); }
catch (Exception e) { e.printStackTrace(); }
}
return new DbAuthorization(userID);
}
|
在这个类中,可以看到抽象类和具体的子类之间的关系,它们是如何协作的,又是如何划分抽象方法和非抽象方法的,这都是值得注意的地方。一般的,抽象方法需要子类来实现,而抽象类中的非抽象方法应该所有子类所能够共享的,或者可是说,是定义在抽象方法之上的较高层的方法。这确实是一个抽象工厂的好例子!虽然实现的方法已经和GOF中给出的实现相差较远了,但思想没变,这儿的实现,也确实是要巧妙的些。
还有就是静态方法的使用,使得这个类看起来有些Singleton的意味。这使得对于AbstractFactory的创建变得简单。
下面的类图给出了这个AbstractFactory的实现的总体情况:
图2:AbstractFactory模式的实现类图
在AuthorizationFactory中定义的其它方法,涉及到具体的如何创建Authorization,都是作为abstract方法出现,具体实现留给子类来完成。
这样,在需要生成一个Authorization的时候,只需要调用AuthorizationFactory的静态方法getAuthorization就可以了,由子类实现了具体的细节。
其它的,如同上面讲到的,在创建Forum的时候用的ForumFactory,具有同上面一样的实现,这就是模式之所以称为模式的所在了。
Proxy模式和权限控制
Proxy模式的功能有很多,比如远程代理,用来给远程对象提供一个本地代表;虚代理,用来为创建开大开销的对象提供缓冲,等等。在Jive中使用的是保护代理,为被保护的对象提供权限控制。
我们都知道在一个论坛中,权限的控制是必须的,否则论坛就很可能会被搞得一团糟。Jive中引入Proxy对象,Authorization接口以及权限描叙属类来提供对论坛的保护。
以ForumFactory为例,一个额外的ForumFactoryProxy来处理权限认证的工作,它为某一个ForumFactory提供了一个代理,保证只有授权的用户才能够存取ForumFactory的某些操作。实际上ForumFactory在这儿不仅仅只是一个生成Forum的类的,它更像是一个Forum的管理类。提供了添加,删除,枚举等等一系列的功能,而有些功能不是什么样的人都可以使用的,因而引入了另外的一个代理类来处理权限的问题。
当然,代理类需要继承ForumFactory,以使方法签名一致: ForumFactoryProxy extends ForumFactory
在它的构造方法中,就提供了一个ForumFactory对象,这是需要被代理的对象;一个Authorization对象,提供用户信息;还有一个ForumPermissions,提供认证信息:
public ForumFactoryProxy(ForumFactory factory, Authorization authorization,
ForumPermissions permissions)
{
this.factory = factory;
this.authorization = authorization;
this.permissions = permissions;
}
|
一般的代理过程都是这样的,在访问某个方法之前,必须接受权限的检查,以createForum为例:
public Forum createForum(String name, String description)
throws UnauthorizedException, ForumAlreadyExistsException
{
if (permissions.get(ForumPermissions.SYSTEM_ADMIN)) {
Forum newForum = factory.createForum(name, description);
return new ForumProxy(newForum, authorization, permissions);
}
else {
throw new UnauthorizedException();
}
}
|
下面给出这个模式的类图:
图3:Proxy模式的类图
这个模式的实现基本上和GOF中所给出的实现一致。在Jive中,几乎所有的接口,Forum,ForumMessage,ForumThread等等,都会有一个相应的Proxy对象来进行权限控制。而在创建具体的对象的时候,都是用相应的Proxy对象来代替原有的对象返回的。例如在ForumFactory的getInstance()方法中需要返回一个Forum的时候,Jive是这样做的:
public static ForumFactory getInstance(Authorization authorization) {
......
ForumFactoryProxy proxy = new ForumFactoryProxy(factory,authorization, factory.getPermissions(authorization));
return proxy;
}
|
因而,所有被创建的对象实际上都是Proxy对象,抽象工厂保证了没有权限验证的对象根本不会客户所得到,它们只会在Proxy的内部扮演角色,而永远不会被外部对象所存取,这样,就从根本上保证了论坛的安全。
Decorator模式和过滤器
一般的在OO设计中,而外功能的添加是通过继承来实现的,但是继承有的时候不够灵活,而且当功能的组合很多的时候,继承的子类就会成几何级数增长,使得类多的难以控制。正是基于这样的考虑,Decorator模式得以诞生。
Decorator模式相当于封装了某个特定的操作,当某个对象需要这个操作的时候,加上这个Decorator即可。并且,多个Decorator还可以组合,以提供更多的功能。
在Jive中,Decorator模式应用在一些过滤器(Filter)中。Filter提供对ForumMessage对象内容的重新构造。比如,当一个ForumMessage对象流过一个名为FilterCodeHighlight的过滤器后,存在于消息中的所有Java源代码文本,会被重新构造为具有语法高亮显示的消息。在比如,当经过了语法高亮修饰的消息再流过一个名为FilterHtml的过滤器后,消息中的HTML片断会被注释可以在HTML内部显示文本,这样就防止了用户输入了HTML控制标签后,使得页面显示不正常的问题。
Jive中,所有的过滤器继承于一个抽象类ForumMessageFilter,而ForumMessageFilter又实现了ForumMessage接口。也就是说,每一个过滤器实际上也是一个ForumMessage对象。
ForumMessageFilter中还封装一个ForumMessage对象。进行过滤的方法很简单,使用的是getBody(),比如在FilterCodeHighlight这个类中:
public String getBody() {
return highlightCode(message.getBody());
}
|
highlightCode是一个private方法,实施具体的过滤的细节。getBody()方法实际上是定义在ForumMessage接口中的,当调用过滤器的getBody()方法时,就能够得到结构重整后的ForumMessage对象了。这个对象可以被其他客户引用,也可以在传递给另外的过滤器,实施进一步的操作。
在实现一个具体的消息的过滤的时候,在Forum中有addForumMessageFilter(),applyFilters()方法,用来实现对过滤器的应用。
对一个Forum,使用addForumMessageFilter()方法添加一个Filter的时候,并没有指定一个具体的Message,而只是一个规则(Filter中封装了过滤规则),然后applyFilter()方法中,实施这些规则:
public ForumMessage applyFilters(ForumMessage message) {
//Loop through filters and apply them
for (int i=0; i < filters.length; i++) {
message = filters[i].clone(message);
}
return message;
}
|
过滤器的clone()方法,为过滤器复制消息体。这个方法的使用,分离了在过滤器中对于消息体和过滤规则的初始化过程,这也是一个值得借鉴的技巧!
下面给出Decorator模式的类图:
图4:Decorator模式的类图
我们可以看到Decorator模式实际上和Proxy模式是很相近的,但是它们代表两个不同的功能含义。Proxy模式提供一个对象的控制,而Decorator模式则是为对象提供额外的功能。
Iterator模式和论坛的浏览erator模式用来分离数据结构和遍历算法,降低两者之间的耦合度,以使得同一个数据结构用不同的算法遍历时,仍能够具有相同的接口,另一方面,Iterator模式使得当改换遍历算法后,不需要更改程序的代码。
在Java的JDK中本身就定义有一个Iterator接口,在Iterator接口中仅仅定义了三个方法,hasNext()判断是否遍历完最后一个元素,next()方法返回要遍历的数据结构中一个对象,remove()则删除当前对象。Jive中使用IteratorProxy抽象类继承了这一接口。这儿Proxy的含义和上面一样,也就是说,这个IteratorProxy出了会实现Iterator的遍历功能外,还会有代理权限控制的功能。
对于论坛中的基本对象Forum,ForumThread,ForumMessage,Group,User都有相应的遍历器。比如对应于Forum接口有ForumIteratorProxy对象。这个ForumIteratorProxy遍历器就相当于一个封装了一系列Forum对象的集合类,通过定义好的接口hasNext()和next()可以方便的遍历这个集合,而并不需要知道是如何遍历这个集合的。遍历的算法可能很简单,也可能很复杂,但是对于外部的客户而言,这并没有任何的区别。
而对于论坛中具体的遍历方法,这取决于具体的实现,在Jive中给出的是数据库的实现。
我们就以MessageIteratorProxy为例,来讲解Iterator模式的用法。
DbThreadIterator对象实现了Iterator接口,是对于一个Thread中所有Message的遍历器,我们来看看它是如何实现的。
hasNext()判断在这个Thread中是不是还有下一条Message:
public boolean hasNext() {
if (currentIndex+1 >= messages.length) {
return false;
}
return true;
}
|
next()方法从数据库中取出与在这个Thread中的下一条Message:
public Object next() throws java.util.NoSuchElementException {
ForumMessage message = null;
if (nextMessage != null) {
message = nextMessage;
nextMessage = null;
}
else {
message = getNextMessage();
if (message == null) {
throw new java.util.NoSuchElementException();
}
}
return message;
}
|
这样,通过对数据库的操作,DbThreadIterator实现了对一个Thread中所有Message遍历的方法。
再ForumThread接口中有messages()方法,返回在这个Thread中的所有Message的一个遍历器(Iterator),实际上也就是返回了一个Message的集合:
public Iterator messages();
在DbForumThread中实现了这个方法:
public Iterator messages() {return new DbThreadIterator(this);}
从DbForumThread的messages()方法中所返回的就是这个Thread中所有Message的一个遍历器,通过这个遍历器,我们就可以访问Thread中的所有的Message了。当然,事情还没有完,由于权限的问题,我们还需要构造这个遍历器的Proxy对象,然后通过这个Proxy对象来访问遍历器。
下面的类图给出了在Jive中Iterator模式的实现方法:
图5:Jive中Iterator模式的实现
在Jive中,因为在一个Thread之下,Message是按树形结构组织的,因而,当需要层级表示一个Thread中的Message之间的关系的时候,仅仅用上面讲到的线性的Iterator是不够的。这时候,对Iterator的概念进行推广,就引入了TreeWalker接口。
顾名思义,TreeWalker提供了遍历一个树和存取树上节点的方法:
public interface TreeWalker {
public ForumMessage getRoot();
public ForumMessage getChild(ForumMessage parent, int index);
public int getChildCount(ForumMessage parent);
public int getRecursiveChildCount(ForumMessage parent);
public int getIndexOfChild(ForumMessage parent, ForumMessage child);
public boolean isLeaf(ForumMessage node);
|
TreeWalker只是Iterator的简单推广,并没有Iterator应用的那么广泛,而且,也可以很容易的在TreeWalker上面在套一层Iterator的借口,让它在某些情况下行使Iterator的职责。这儿就不再多讨论了。
再此,Jive设计中所有涉及到的设计模式的地方,基本上都讲完了,看完了之后,是不是对设计模式有了更进一步的了解了呢?
下一部分的内容,将会涉及到具体的编码,深入到JSP的内部,我们将会看到Jive中是如何实现可更换的Skin的,还会涉及Tag Library的一些内容。好了,这次就到这儿了。下次再见。
转载自http://hi.baidu.com/ahunspun/blog/item/0069084e9882a0cbd0c86a66.html
一. Input和Output
1. stream代表的是任何有能力产出数据的数据源,或是任何有能力接收数据的接收源。在Java的IO中,所有的stream(包括Input和Out
stream)都包括两种类型:
1.1 以字节为导向的stream
以字节为导向的stream,表示以字节为单位从stream中读取或往stream中写入信息。以字节为导向的stream包括下面几种类型:
1) inputstream:
1) ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用
2) StringBufferInputStream:把一个String对象作为InputStream
3) FileInputStream:把一个文件作为InputStream,实现对文件的读取操作
4) PipedInputStream:实现了pipe的概念,主要在线程中使用
5) SequenceInputStream:把多个InputStream合并为一个InputStream
2) Outputstream
1) ByteArrayOutputStream:把信息存入内存中的一个缓冲区中
2) FileOutputStream:把信息存入文件中
3) PipedOutputStream:实现了pipe的概念,主要在线程中使用
4) SequenceOutputStream:把多个OutStream合并为一个OutStream
1.2 以Unicode字符为导向的stream
以Unicode字符为导向的stream,表示以Unicode字符为单位从stream中读取或往stream中写入信息。以Unicode字符为导向的stream包括下面几
种类型:
1) Input Stream
1) CharArrayReader:与ByteArrayInputStream对应
2) StringReader:与StringBufferInputStream对应
3) FileReader:与FileInputStream对应
4) PipedReader:与PipedInputStream对应
2) Out Stream
1) CharArrayWrite:与ByteArrayOutputStream对应
2) StringWrite:无与之对应的以字节为导向的stream
3) FileWrite:与FileOutputStream对应
4) PipedWrite:与PipedOutputStream对应
以字符为导向的stream基本上对有与之相对应的以字节为导向的stream。两个对应类实现的功能相同,字是在操作时的导向不同。如
CharArrayReader:和ByteArrayInputStream的作用都是把内存中的一个缓冲区作为InputStream使用,所不同的是前者每次从内存中读取一个
字节的信息,而后者每次从内存中读取一个字符。
1.3 两种不现导向的stream之间的转换
InputStreamReader和OutputStreamReader:把一个以字节为导向的stream转换成一个以字符为导向的stream。
2. stream添加属性
2.1 “为stream添加属性”的作用
运用上面介绍的Java中操作IO的API,我们就可完成我们想完成的任何操作了。但通过FilterInputStream和FilterOutStream的子类,我们可以
为stream添加属性。下面以一个例子来说明这种功能的作用。
如果我们要往一个文件中写入数据,我们可以这样操作:
FileOutStream fs = new FileOutStream(“test.txt”);
然后就可以通过产生的fs对象调用write()函数来往test.txt文件中写入数据了。但是,如果我们想实现“先把要写入文件的数据先缓存到内存
中,再把缓存中的数据写入文件中”的功能时,上面的API就没有一个能满足我们的需求了。但是通过FilterInputStream和FilterOutStream的
子类,为FileOutStream添加我们所需要的功能。
2.2 FilterInputStream的各种类型
2.2.1 用于封装以字节为导向的InputStream
1) DataInputStream:从stream中读取基本类型(int、char等)数据。
2) BufferedInputStream:使用缓冲区
3) LineNumberInputStream:会记录input stream内的行数,然后可以调用getLineNumber()和setLineNumber(int)
4) PushbackInputStream:很少用到,一般用于编译器开发
2.2.2 用于封装以字符为导向的InputStream
1) 没有与DataInputStream对应的类。除非在要使用readLine()时改用BufferedReader,否则使用DataInputStream
2) BufferedReader:与BufferedInputStream对应
3) LineNumberReader:与LineNumberInputStream对应
4) PushBackReader:与PushbackInputStream对应
2.3 FilterOutStream的各种类型
2.2.3 用于封装以字节为导向的OutputStream
1) DataIOutStream:往stream中输出基本类型(int、char等)数据。
2) BufferedOutStream:使用缓冲区
3) PrintStream:产生格式化输出
2.2.4 用于封装以字符为导向的OutputStream
1) BufferedWrite:与对应
2) PrintWrite:与对应
3. RandomAccessFile
1) 可通过RandomAccessFile对象完成对文件的读写操作
2) 在产生一个对象时,可指明要打开的文件的性质:r,只读;w,只写;rw可读写
3) 可以直接跳到文件中指定的位置
4. I/O应用的一个例子
import java.io.*;
public class TestIO{
public static void main(String[] args)
throws IOException{
//1.以行为单位从一个文件读取数据
BufferedReader in =
new BufferedReader(
new FileReader("F:\\nepalon\\TestIO.java"));
String s, s2 = new String();
while((s = in.readLine()) != null)
s2 += s + "\n";
in.close();
//1b. 接收键盘的输入
BufferedReader stdin =
new BufferedReader(
new InputStreamReader(System.in));
System.out.println("Enter a line:");
System.out.println(stdin.readLine());
//2. 从一个String对象中读取数据
StringReader in2 = new StringReader(s2);
int c;
while((c = in2.read()) != -1)
System.out.println((char)c);
in2.close();
//3. 从内存取出格式化输入
try{
DataInputStream in3 =
new DataInputStream(
new ByteArrayInputStream(s2.getBytes()));
while(true)
System.out.println((char)in3.readByte());
}
catch(EOFException e){
System.out.println("End of stream");
}
//4. 输出到文件
try{
BufferedReader in4 =
new BufferedReader(
new StringReader(s2));
PrintWriter out1 =
new PrintWriter(
new BufferedWriter(
new FileWriter("F:\\nepalon\\ TestIO.out")));
int lineCount = 1;
while((s = in4.readLine()) != null)
out1.println(lineCount++ + ":" + s);
out1.close();
in4.close();
}
catch(EOFException ex){
System.out.println("End of stream");
}
//5. 数据的存储和恢复
try{
DataOutputStream out2 =
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("F:\\nepalon\\ Data.txt")));
out2.writeDouble(3.1415926);
out2.writeChars("\nThas was pi:writeChars\n");
out2.writeBytes("Thas was pi:writeByte\n");
out2.close();
DataInputStream in5 =
new DataInputStream(
new BufferedInputStream(
new FileInputStream("F:\\nepalon\\ Data.txt")));
BufferedReader in5br =
new BufferedReader(
new InputStreamReader(in5));
System.out.println(in5.readDouble());
System.out.println(in5br.readLine());
System.out.println(in5br.readLine());
}
catch(EOFException e){
System.out.println("End of stream");
}
//6. 通过RandomAccessFile操作文件
RandomAccessFile rf =
new RandomAccessFile("F:\\nepalon\\ rtest.dat", "rw");
for(int i=0; i<10; i++)
rf.writeDouble(i*1.414);
rf.close();
rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "r");
for(int i=0; i<10; i++)
System.out.println("Value " + i + ":" + rf.readDouble());
rf.close();
rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "rw");
rf.seek(5*8);
rf.writeDouble(47.0001);
rf.close();
rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "r");
for(int i=0; i<10; i++)
System.out.println("Value " + i + ":" + rf.readDouble());
rf.close();
}
}
关于代码的解释(以区为单位):
1区中,当读取文件时,先把文件内容读到缓存中,当调用in.readLine()时,再从缓存中以字符的方式读取数据(以下简称“缓存字节读取方
式”)。
1b区中,由于想以缓存字节读取方式从标准IO(键盘)中读取数据,所以要先把标准IO(System.in)转换成字符导向的stream,再进行
BufferedReader封装。
2区中,要以字符的形式从一个String对象中读取数据,所以要产生一个StringReader类型的stream。
4区中,对String对象s2读取数据时,先把对象中的数据存入缓存中,再从缓冲中进行读取;对TestIO.out文件进行操作时,先把格式化后的信
息输出到缓存中,再把缓存中的信息输出到文件中。
5区中,对Data.txt文件进行输出时,是先把基本类型的数据输出屋缓存中,再把缓存中的数据输出到文件中;对文件进行读取操作时,先把文
件中的数据读取到缓存中,再从缓存中以基本类型的形式进行读取。注意in5.readDouble()这一行。因为写入第一个writeDouble(),所以为了
正确显示。也要以基本类型的形式进行读取。
6区是通过RandomAccessFile类对文件进行操作。