??xml version="1.0" encoding="utf-8" standalone="yes"?>
目的是惛_公司能很方便的访问家里那些收集很久电(sh)子书Q方便查阅?br />
用了(jin)1Q?个星期,虽然写的很烂Q但是没有用MW三方的产品Qserver or dbQ?br />
现在里面的书c已l接q?00本了(jin)?br />
注:(x)serverq?jin)家里的adslQ所以速度慢,关闭不定时。毕竟玩玩嘛?br />
有兴的朋友先装个jdk1.5。再q行下面压羃包里的exe文g执行卛_?br />
Ҏ(gu)下蝲
User ID: blogjava
Password: blogjava
重点x对象的创建和销毁:(x)什么时候、如何创建对象,什么时候、什么条件下应该避免创徏对象Q如何保证对象在合适的方式下被销毁,如何在销毁对象之前操作一些必ȝ清理行ؓ(f)?/span>
如果一?/span> client 要实例化一个对象来使用Q傻 b 都知道应该先调用cȝ构造器?/span> new 一个对象,之后再调用相应的Ҏ(gu)。除?jin)这个方式?/span> Java Effective q徏议了(jin)另一U方法:(x)用静(rn)态工厂方法来提供一个类的实?/u>。以下的例子不反映两者的优劣Q只是反映两者在代码实现上的不同Q优劣之后再谈:(x)
假设׃要一个颜色ؓ(f)黑色、长度ؓ(f)
Hammer myHammer = new Hammer(Color.BLACK, 50);
而用?rn)态工厂方法来实例化一个对象,如下
Hammer myHammer = Hammer.factory(Color.BLACK,50);
也可以用专门的一个工厂类来实例化
Hammer myHammer = Toolkit.factory(“Hammer? Color.BLACK,50);
单纯从上面的代码上看Q真的只有傻 b 才会(x)选择?rn)态工厂的Ҏ(gu)Q完全就是多此一举,直接 new 又快又爽Q搞q么ȝ(ch)做莫斯(武汉话“什么”的意思)(j)Q?/span>
别急,别急,你急个?/span> b Q武汉粗话:(x)基本是“你急个毛”的意思)(j)Q?/span>
下面p说用?rn)态工厂代替构造器的好处( advantage Q和不好处( disadvantage Q?/span>
W一个好处,讲你都不信,行家们认为,构造器有一个不好的地方是Q这个方法的{Q?/span>
signture
Q太固定?jin)?/span>
构造器的名字是固定的,生个 Hammer Q构造器的名字就?/span> Hammer Q……)(j)Q唯一能变化的地方是参数Q假设我的这个锤子有两个很变态的构造需要:(x)
1 Q第一个参数是颜色Q?/span> Color 型)(j)Q第二个参数是锤子头的重量( int 型)(j)?/span>
Hammer Q?/span> Color c, int kg Q?/span> {
//remainder omited
}
2 Q第一个参数是颜色Q?/span> Color 型)(j)Q第二个参数是锤子的长度Q?/span> int 型)(j)?/span>
Hammer Q?/span> Color c, int cm Q?/span> {
//remainder omited
}
感觉满需要了(jin)Q但是细?j)一看,完了(jin)Q构造器的参数列表类型重复了(jin)Q肯定编译通不q,q是面向对象构造器天生的缺陷——唯一的变化就是参敎ͼ参数都分辨不?jin),q的分辨不?jin)?/span>
而另外就参数能分L的了(jin)Q构造器一多,它的参数一多,(zhn)根本就不知道每个参数是用来q什么的Q只能去查阅文档Q在(zhn)已l眼qq时候再L文档Q一个一个的对,折磨人的zR?/span>
q个时候,(zhn)就可以考虑用静(rn)态工厂方法来实例化对象了(jin)。因为静(rn)态工厂方法有一个最单的特点是Q他有可以变化的Ҏ(gu)名(构造器的名字变不了(jin)Q。用名字的不同来代表不同的构造需要,q么单的普通的特点在这里就是它相对于构造器?/span> advantage ?/span>
如上面的锤子的例子可以这P(x)
1 Q?/span> Hammer.produceByWeight (Color c, int kg){
//remainder omited
}
2 Q?/span> Hammer.produceByHeight (Color c, int cm){
//remainder omited
}
q是不是一目了(jin)然多?jin)。嗯Q我是这栯为的?/span>
W二个好处,“静(rn)态工厂方法不需要每ơ都真的d例化一个对象”——其实这也是另一些优化方法的前提?/span>
构造器的每?/span> invoke 必定?x)生一个新的对象,而静(rn)态工厂方法经q一定的控制Q完全可以不用每?/span> invoke 都生成一个新的对象?/span>
Z么不每次都生成一个对象的原因׃必说?jin),因?f)原因太明显。这个原因就是ؓ(f)什么要“共享”对象的原因?/span>
下面讲讲通常使用的两U共享具体策略,也就是具体方法了(jin)Q?/span>
1 Q单例模式的需要,一旦需要某个对象有单例的需要,必定对于q类对象的构造只能用?rn)态工厂方法了(jin)?/span>
2 Q?/span> flyweight 模式和不变( immutable Q?/span> 模式的需要,q两个模式很多时候都说一起用的Q一旦一些对象我们认为是不变的,那自然就x来重用,也就说共享,?/span> flyweight 是用来重用q些粒度对象的?/span>
?/span> Boolean.valueOf (boolean) Ҏ(gu)Q?/span>
Boolean a = Boolean.valueOf (100);
Boolean b = Boolean.valueOf (100);
aQ?span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal">
b两个引用都是指向同一个对象?/span>
q些对象都是不变的,?/span> valueOf 的控制就是用?/span> flyweight Ҏ(gu)?/span>
q种一个状态(如上面一个数字)(j)对应的对象只有一个还有一个好处,是可以直接通过比较“引用”来判断他们是否
equel
Q这里的
equel
是逻辑相等的意思)(j)Q以前需?/span>
a.equels(b)
Q而一旦用?/span>
flyweight
模式和不变(
immutable
Q?/span>
模式”后Q避免了(jin)产生多余的相同对象,?/span>
a==b
可以达?/span>
a.equels(b)
的目的了(jin)。这样当然优化了(jin)
performance
?/span>
W三个好处,其实是工厂Ҏ(gu)的核?j)好处——我把它UCؓ(f)“抽象类型构造器”。它可以为我们提供一个抽象类型的实例Q同时必要的隐藏?jin)抽象类型的具体l构。这?/span>
new
怎么都达不到的?/span>
q种模式的好处其实就是面向对象的最核心(j)的好处,抽象和具体可以分,一旦抽象定义好?jin),具体的东西可以慢慢的变化Q慢慢的拓展——开闭原则?/span>
?/span>
Collections Framework API
Q都是描q集合类型的接口Q也是对于客户端来看,只有
Collection
q个c要认识Q而实际上Q实现这个接口的
Collection
是多U多L(fng)。如果要让用户都知道q些具体实现?/span>
Collection
Q就增加?jin)复杂度?/span>
q时Q通过一个静(rn)态工厂方法,可以隐藏各U?/span>
Collection
的具体实玎ͼ而让
Client
只用返回的
Collection
对象可以了(jin)?/span>
q里q可以加上一些权限控Ӟ如这些实现只要对于工厂来讲是可以讉K的,不用?/span>
public
的,而他们只要通过
public
的工厂就可以提供l用戗非常有利于代码的安全?/span>
?rn)态工厂方法的W一个缺点就是:(x)使用?rn)态工厂方法创建的cȝ构造器l常都是非公共或?/span>
protected
的?/span>
q样Q以后这些类没有办法被l承?jin)。不q也有h_(d)不用l承q
composition
呗。也是!呵呵?/span>
?rn)态工厂方法的W二个缺Ҏ(gu)Q在
jdk
文档里,q些?rn)态工厂方法很难跟别的?rn)态方法相区别?/span>
而文档中Q构造器是很Ҏ(gu)看到的?/span>
Z(jin)一定程度解册个问题,我们可以用一些比较特别的名字来给q类?rn)态工厂方法来命名。最常用的有Q?/span>
valueOf
—?/span>
用来攑֛跟参数“相同值”的对象?/span>
getInstance
—?/span>
q回一个对象的实例。单例模式中Q就是返回单例对象?/span>
ȝQ静(rn)态工厂方法和构造器都有各自的特炏V最好在考虑用构造器之前能先考虑一下静(rn)态工厂方法,往往Q后者更有用一炏V如果权衡了(jin)以后也看不出那个好用一些,那就用构造器Q毕竟简单本分多?jin)?/span>
׃n?/SPAN>idea是生zM最基本?/SPAN>ideaQ不必有意的使用Q到处已l存在了(jin)。在生活中,大部分事物都是被多h多次使用的,q都是共享的实际应用?/SPAN>
之于OO的共?/SPAN>
OO中的׃nQ无非就是说让“对象”也能被“多人多ơ”(q里的“h”也无非是q程、线E而已Q用,更详l的_(d)是要让对象的生存空间更大一些,生存周期更长一些?/SPAN>
自己闷个儿脑子,提炼Z(jin)几个需要用共享的环境Q?/SPAN>contextQ,也可以说是原因吧Q?/SPAN>
1. Z(jin)保持“对象”的一_(d)我们需要共享。例如,“国家主席”就一个,不能多了(jin)Q如果多?jin),隑օ决策混ؕ?/SPAN>
2. Z(jin)控制“对象”的存储I间Q我们需要共享。毕竟,目前来说Q系l的memoryq是~程时最珍贵的资源?/SPAN>
3. Z(jin)优化“对象”的创徏消耗,我们需要共享。如果,一个对象的创徏q程消耗太大,pȝ不能支持频繁的创建,׃n的用它也是一个好L?/SPAN>
4. {等?/SPAN>
而在实际的应用中Q往往我ƈ没有l想“我Z么用共享?”,已经不自觉的q?jin);如果真的认真分析hQ基于的环境也是多样Qƈ不会(x)只是上面的其中一U?/SPAN>
常用的“共享”方法或模式Q我曄用过的,知道的不多,望谅解)(j)Q?/SPAN>
1. ?/SPAN>Singleton模式”:(x)一?/SPAN>class׃个对象实例,大家都用它,满context1?/SPAN>
2. ?/SPAN>pool技术”:(x)只提供一定数目的对象Q大安用他们,实现context2?/SPAN>context3?/SPAN>
3. ?/SPAN>flyweight模式”:(x)一?/SPAN>class的一个状态就一个对象实例,实现一个状态对象的׃nQ实?/SPAN>context2?/SPAN>context3?/SPAN>
使用时要注意的地方:(x)
1. 定׃n?/SPAN>scope。例如,?/SPAN>Java Web Application中就是选择?/SPAN>pageQ?/SPAN>sessionq是applicationQ当然也可以?/SPAN>jvmU别?/SPAN>static?/SPAN>
2. 认thread safe。当׃n的对象可能被多个U程׃nӞq是不可以回避的问题?/SPAN>
3. 应对对象状态的变化。一旦共享的对象发生?jin)变化,我们怎么处理Q改变之Q舍弃之Q也是我们需要确定的?/SPAN>
目中的应用Q?/SPAN>
目需求:(x)
为学校的同学提供Web查询Q查询的内容有很多。其中,“查课表”、“查考表”是最为关键的需求,以后可能q要提供“查询空闲自?fn)教室”的功能?/SPAN>
在这些查询中Q有一个共同点Q就是都涉及(qing)“教室”这一对象。“查课表”时要告诉同学在哪个教室上课Q“查考表”时要告诉同学在哪个教室考试Q等{?/SPAN>
数据库设计:(x)
对于“查课表”用例,有关的数据库设计如下Q?/SPAN>
对象层的设计Q?BR>
学生每查询一门课E的课表Q系l就?/SPAN>sql查询“视?/SPAN>V_LESSONSCHEDULE”,q而生成一?/SPAN>LessonSchedule对象Q然后返回给用户昄。当?dng)在生成这?/SPAN>LessonSchedule对象的过E中Q属于它?/SPAN>Classroom对象Q以?qing)更׃步的Building?/SPAN>Area对象都会(x)生成。下面就是这个过E的序图:(x)
因此Q每生成一个“课表”对象(LessonScheduleQ或“考表”对象(ExamScheduleQ时Q都要:(x)
1. 查数据库中的教室、教学楼、校区的信息Q?/SPAN>
2. 创徏相应的“教室对象”(包括?jin)属于它的“教学楼”对象和“校区”对象)(j)?/SPAN>
考虑׃n“教室”对?/SPAN>
“教室”对象一旦可以生成以后,完全可以l后l共享用,不必要每个查询都要去生成?/SPAN>
详细说是Z下面的考虑Q?/SPAN>
1. q类查询用例Q查课表Q查考表Q发生的频繁很高很高Q也是_(d)一旦让用户查v来,pȝ中会(x)产生大量的“教室”对象这cd象,应该说会(x)占很大的内存I间?/SPAN>
2. ׃n“教室”对象后Q可以减对数据库的查询ơ数Qƈ降低?jin)查询粒度(以前是基于二U视图查询,现在可以Z基本表查询)(j)Q提高了(jin)一Ҏ(gu)据库查询性能?/SPAN>
当然Q同时我脑袋中也有反对的声音Q?/SPAN>
1. 虽说Q这cL询会(x)产生很多相同的“教室”对象,但是JVM本生提供的垃圑֛收功能完全可以处理它。除非,“同时”有很多很多q类对象都在被用,Ҏ(gu)回收不了(jin)Q才?x)造成内存短缺?/SPAN>
2. 如果Q我以某U共享机制让q些“教室”对象,在系l中存在下来Qg长了(jin)生命周期Q了(jin)。而它们本w的数目很多(如,我们学校有××Q,可能q没有等你用上,pȝ已经挂了(jin)。另外,如果不是同时有很多查询需要,我留q么多“教室”对象在pȝ里,反而是占了(jin)内存Q而不是优化了(jin)内存的用?/SPAN>
1. 所有模式的通病――“增加了(jin)复杂度”?/SPAN>
l论Q?/SPAN>
l过我们分析Q系l对于“教室”对象的重复使用Q频J程度非帔R。一般,?/SPAN>10个h同时使用Q就?/SPAN>5个h左右涉及(qing)的用例要使用“教室”对象。把它共享v来,q是有一定必要的?/SPAN>
q一步考虑Q?/SPAN>
而实际上Q我们可以进一步共享下去:(x)
除了(jin)让客L(fng)׃n“教室对象(ClassroomQ”外Q还可以让“教室对象”共享“教学楼对象Q?/SPAN>BuildingQ”,和让“教学楼对象”共享“校区对象(AreaQ”?/SPAN>
因此Q最l的׃n是在三上都实现?/SPAN>
Flyweight模式Q?/SPAN>
特点Q?/SPAN>
书上_(d)(x)“n元模式可以ɾpȝ中的大量粒度对象被׃n使用”。第一Q对象出现的量要大,惛_q比较好理解Q很用的也就没有必要׃n?jin);W二Q要粒度,我比较纳PN对于大粒度对象就不行吗?可能书上认ؓ(f)Q大_度对象的共享已l占?jin)比较大的空_(d)没有对象那么有效吧?/SPAN>
另外Q书上还_(d)要用“n元模式”,被共享的对象的状态(cdQ要比较固定Q这样就可以为每一个状态仅仅创Z个对象。当?dng)如果每次使用对象Ӟ对象的状态都是不一L(fng)Q那根本不存在׃nq些对象的必要了(jin)?/SPAN>
联系目思考:(x)
Z上面寚w目的分析Q“教室”、“教学楼”、“校区”对象都是在pȝ中会(x)被大量用的对象Q而且_度的确比较?yu);q且它们有固定的cdQ而且不易改变。如校区对象Q暂时就?/SPAN>4个。教学楼可能40Q?/SPAN>50个左叟뀂很适合“n元模式”的使用环境?/SPAN>
定׃n方式Q?/SPAN>
1. 定׃n对象?/SPAN>scope。在?/SPAN>webE序中,q些׃n对象?/SPAN>scope理应?/SPAN>applicationQ而更单的一个作法就是把q些对象设ؓ(f)staticQ我选择后者?/SPAN>
2. 认thread safe。这些对象是可能被多?/SPAN>servlet讉K的,也就是有可能存在多线E访问。但是,׃q些对象的可变性很差,一旦创建就不大可能变化。因此,我决定把q写׃n对象设计成不变模式的Q一旦创建就只会(x)被读取,而不?x)改写,q样׃存在多线E控制的问题?jin)?/SPAN>
3. 应对对象状态的变化Q如某个教室的类型变?jin)。这里采取的是舍弃的Ҏ(gu)Qؓ(f)每个工厂d?jin)一个清I方法―?/SPAN>clear()Q用于清I已l生成的׃n对象?/SPAN>
设计cdQ?/SPAN>
当然Q也可以把这些工厂都设计成?/SPAN>Singleton模式”的Q它们只会(x)有一个实例?/SPAN>
客户端用:(x)
׃׃n的对象都被包含在?jin)“课表”和“考表”对象里Q不?x)被客户端直接访问,因而不?x)对客户端的使用有Q何媄(jing)响:(x)
实例代码
oneClassroom?/SPAN>twoClassroomQ?/SPAN>oneBuilding?/SPAN>twoBuildingQ?/SPAN>oneArea?/SPAN>twoArea׃都是32可E的东西Q根据我们的设计意图Q应该实现共享?/SPAN>
而实际上Q它们每对的是同一个对象的引用。因此,实现?jin)预期的设想?/SPAN>
ReviewQ?/SPAN>
在本目中,当第一ơ设计出来的时候,我们发现?jin)某些对象恰好有׃n的需要?/SPAN>
而更多的实际情况是,q些需要共享的“信息或状态”在设计中ƈ不是那么恰好的表Cؓ(f)“一个对象”的_度Q而是要不包含在一个对象内部,要不p几个对象。在q样的情况下Q共享的设计更多是发生在代码重构阶段而不是第一的设计阶Dc(din)当?dng)Z(jin)׃n对象而做出的代码重构Q最重要的一步就是把需要共享的“信息或状态”设计成为新的对象?/SPAN>
对于Q“n元模式”来_(d)是要把需要共享的“信息或状态”设计成“n元对象”。别的在此就不说?jin),因?f)我也不懂?jin),呵呵?/SPAN>
MARCO ZHANG 2006q??3?3:48:49
预料中的日志3暂时生不出来,话说难好Q别夭折pQ有Ҏ(gu)价哦Q呵c(din)?/SPAN>
因ؓ(f)有些东西q没有想清楚。那先搞个四吧Q这个东西还是清楚那么一点的?/FONT>
目需?/SPAN> |
使每?/SPAN>servlet能对用户讉K权限q行(g)查。简单来_(d)是要给每个servlet加个锁,有钥匙的用户才能讉K?/SPAN> |
而项目中用户所谓的讉K权限是基于他拥有的角艌Ӏ也是_(d)servlet对用戯问权限的(g)查,是对他所拥有角色的检查。暂Ӟ每个用户只能拥有一个角艌Ӏ?/SPAN>
目的角色很多,但是?/SPAN>web端暂时只有如下的三种Q?/SPAN>
目暂时角色 |
游客Q学生,教师 |
既然q样Q?/SPAN>servlet的加锁方式就有:(x)
servlet加锁方式 |
游客Q学生,教师Q?BR>游客或学生,游客或教师,学生或教师, |
注:(x)上面的“游客”就是“游客角色有权访问”的意思,依此cL?/FONT>
q里只有关系“或”(||Q,如果一?/SPAN>servlet的加锁方式是“学生或教师”,也就是说拥有学生或教师角色的用户都可以访问它。关pZ与”(&&Q在q里不太可能存在Q因为没有需求说Q某?/SPAN>servlet一定只能由“既是学生又是教师的用户”才能访问,而且前面也说?jin),暂时一个用户“有且只有”一个角艌Ӏ?/SPAN>
So we can get following functionQ?BR>
|
q用OO的最基本方式Q就是封装对象。既然有?/SPAN>servlet“看门”的责QQ那把q个责Q装成一个对象,用个俗名Q?/SPAN>validator?/SPAN>
接着Q运用共性和个性的分析Ҏ(gu)Q既然有那么多种不同的看门方式(加锁方式Q,那就搞一个接口,然后让各U“不同”都实现q个接口QŞ成子cR那有下面的图Q?/FONT>
可以看到Q由于有7个加锁方式,那就要有7个子cR每个子cL据自己逻辑override接口?/SPAN>validateҎ(gu)?/SPAN>
q样Q对于一?/SPAN>servletQ想让它上什么样的锁Q只要让它拿到对应的子类的引用即可,如下图中?/SPAN>ClientServletQ我们规定只能有“学生或教师”才能访问它。它的部分代码便是:(x)
xQ第一个解x案就出来?jin)?/FONT>
不 |
validator接口的子cL目随“角色数”成“指数”增长,数量太多Q而且子类中重复逻辑的代码很多,如?/SPAN>Student_Or_Teacher_Validator”就重复?jin)?/SPAN>Student_Validator”和?/SPAN>Teacher_Validator”的逻辑Q万一?/SPAN>Student_Validator”的逻辑要改Q只要涉?/SPAN>Student的子c都要跟着改,l护上不方便?/SPAN> |
q一步改q的可能 |
?/SPAN>Student_Or_Teacher_ValidatorcZ的validateҎ(gu)很大E度上就是?/SPAN>Student_ValidatorcZ的validateҎ(gu)和?/SPAN>Teacher_ValidatorcZ的validateҎ(gu)“或操作”出来的l果?/SPAN> 因此Q能不能考虑由?/SPAN>Student_ValidatorcȝvalidateҎ(gu)”和?/SPAN>Teacher_Validator?/SPAN>validateҎ(gu)?B style="mso-bidi-font-weight: normal">动态的构?/SPAN>一个功能如?/SPAN>Student_Or_Teacher_ValidatorcȝvalidateҎ(gu)”?/SPAN> q样Q?/SPAN>Student_Or_Teacher_Validator”就可以省略?jin),只剩下一些原子的“角色类”。要实现Student_Or_Teacher_Validator的验证功能,?/SPAN>Student_Validator?/SPAN>Teacher_Validator装配一下就可以?jin)?/SPAN> |
l论Q需要根据实际情况,动态的改变Q装配)(j)?/SPAN>Validator接口对象”的validateҎ(gu)?/SPAN>
W一个火花就是“装饰模式”。它可以让客L(fng)动态的l装对象的方法。真奇Q?/FONT>
注:(x)上图中出C(jin)AndRelation?/SPAN>And的一pd角色c,可以暂时省略不看Q因为前面说?jin),现在q没有“与”关p这个需求。只?/SPAN>Or的就可以?/SPAN>
我喜Ƣ叫q个模式为洋葱模式,一层包一层,最外层对象某方法的逻辑是由内部一层一层对象的同一Ҏ(gu)l合出来的?/FONT>
使用?jin)这个模式,便不用如一版那样实现那么多子类Q只要实现几个“角色类”即可,q里?/SPAN>3个(学生角色Q?/SPAN>Or_Student、教师角Ԍ(x)Or_Teacher、游客角Ԍ(x)Or_GuestQ。所有一版中别的子类都可以由q?/SPAN>3个组装出来?/SPAN>
如要生成一版中?/SPAN>Student_Or_Teacher_Validator对象Q可以用Or_Student?/SPAN>Or_Teacher两个对象?/SPAN>Or”出来:(x)
如要生成一版中?/SPAN>Guest_Or_Student_Or_Teacher_Validator对象Q可以用Or_Student?/SPAN>Or_Teacher?/SPAN>Or _Guest三个对象?/SPAN>Or”出来:(x)
q种一层包一层的new方式Q是不是很像z葱Q第一ơ看是很不习(fn)惯,看多?jin)就觉得习(fn)惯了(jin)?/SPAN>
一版中Q客L(fng)要什么样的验证类Q就直接使用具体cR?/FONT>
二版中,客户端要什么样的验证类Q它的工作多?jin)那么一丁点Q它需要先l装一下,正如上面的例子。这U组装的Ҏ(gu)很易于理解和使用Q不?x)给客户端带来Q何的不便。如果实在觉得客L(fng)l装不出来(?/SPAN>B客户端)(j)Q也可以搞个工厂l它supplyQ?/SPAN>
相对一版最明显的优点就是类的数目少?jin)很多?/FONT>
一版不是说“指数”吗Q这里只是线性的?jin)。假设某一天系l拓展到?/SPAN>10个角Ԍ一版就?/SPAN>2?/SPAN>10ơ方那么多个Q也是1024个验证类?/SPAN>
而二版还?/SPAN>10个角色类Q别的都可以在客L(fng)使用的时候,动态的l装
更重要的是代码结构好?jin),重复逻辑了(jin)。每个逻辑都以最atomic的大放到最应该的地斏V?/SPAN>
q而,l护的代价少多了(jin)。如某天“教师角艜y(c)的验证逻辑发生?jin)变化,只要改?/SPAN>Or_Teacher一个地方即可?/SPAN>
MARCO ZHANG 2006q??8?3:49:56
研究生院目中“明䏀用了(jin)“工厂方法模式”。其实在遇到具体问题的时候,即我们不知道有q个模式存在Q我们也肯定?x)造一个类似的东西出来。但是,肯定没有书上的那么好Q那么全面。我惌是看书的好处吧?/SPAN>
工厂Ҏ(gu)出现的必?dng)我的理解Q一个很狭隘q幼E理的h的理解)(j)
刚开始用这个东西的时候,只是感觉是单U的一U模式,用于创徏需要的对象?/SPAN>
但是随着使用和思考的深入Q越发发现它l我的启CZ只在于单U的对象创徏Q而是告诉我应该怎么理解“品”,怎么得到“品”,怎么消费“品”,以至于以后怎么设计“品”?/SPAN>
下面q个U烦(ch)是我对它出现必然性的理解Q?/FONT>
1. “针Ҏ(gu)口编E?/FONT>
q是OO世界中经典的规范Q不你dq是被动Q你天天都在用这个东ѝ?/SPAN>
接口是共性的表示Q在对象的世界中Q共性和个性的辩证关系是最重要的关pR在万千的对象中Q通过它们之间的共性和个性,可以形成最基本对象层架构?/SPAN>
假设我们的讨论域中有以下一些对象:(x)“学生”、“大学生”、“小学生”、“中学生”;我们不用l想Q学q一?/SPAN>OO的h都可以ؓ(f)q些耳熟能详的对象们Q通过个性和共性的关系得出下面的结构图?BR>
把这些对象之间的关系定义成这h理成章的?/SPAN>
下一步肯定是让客L(fng)“用”这个接口啦。也是如下图:(x)
2. 接口和具体类的矛?/FONT>
勿庸|疑Q我们只希望Client跟接?/SPAN>Student打交道,让它Ҏ(gu)׃知道Student有哪些子c,l对不希望直接跟它们打交道?/SPAN>
但这里出现的困难是,接口都是“假”的Q都是由具体c?/SPAN>upcast的?/SPAN>
如果Client要用接?/SPAN>StudentQ?/SPAN>Client中必M(x)出现下面的代码:(x)
Student marco = new Small_Student();
只要一出现q个代码Q就说明Client不只?/SPAN>Student打交道了(jin)Q它知道?/SPAN>Small_Studentc,q违反了(jin)我们预先的想法?/SPAN>
3. 䏀h”帮我去创徏“接口对象?/FONT>
从上图体现出来的l构看,Client只想?/SPAN>Student打交道的目的是实C?jin)的了(jin)?/SPAN>
最单的Ҏ(gu)是扑֏外的“帮手”去帮我生成q个“接口对象”。这个帮手它知道“接口对象”的具体cdQ但是它为客L(fng)提供的却一定是“接口类型”。这q合我们的要求?jin)。如图:(x)
q样Q?/SPAN>Client可以既用到?jin)?/SPAN>Student接口对象”,又不用因为“只有具体类才能创徏对象”的规则Q而必d其子cȝ构有完全的了(jin)解。它成功的解决了(jin)2中的矛盾?/SPAN>
而“负责创建具体类对象的Q务”全部都落在?jin)这个“帮手”n上,q个“帮手”(Student_FactoryQ就是工厂模式中的工厂类Q更具体的说Q它?yu)是“简单工厂模式”中的“简单工厂类”?/SPAN>
我觉得,即一炚w不知道工厂模式,一旦我遇到?/SPAN>2里说的矛盾,我也?x)用q样的方法处理?/FONT>
4. q个“帮手”不W合“开Q闭原则?/FONT>
q个帮手的确不错?jin),而且一跃成为系l中最重要的对象了(jin)Q所有“创建具体类的逻辑”都放进M(jin)Q也是因ؓ(f)重要Q万一挂了(jin)不就惨了(jin)?/FONT>
再者,它不W合“开Q闭”原则,我不能在不修改这个帮手的情况下添加Q何一个品。在q个例子中就是,如果那天我有病非要加一个“幼儿园学生”进来,那?zhn)必M改这个“帮手”的代码?jin),q个“帮手”现在就变成Version2Q如下图Q了(jin)Q这个二版的帮手Q可以在“代码”层实现对一版(q没有添加幼儿园学生之前)的通用Q但q种保证在“开Q闭”原则看来,q是不够的,不保险的Q它要的是在cȝl构上的保证。声明一下,q是我很感性的理解Q不正确的可能性很高?BR>
5. 让“帮手”也多?/FONT>
q里可以试让“帮手”也多态一下,q样“每U学生类创徏的Q务”都被分zֈ?jin)多态出来的cMM(jin)。这Ӟ再有新的学生cd加进来,d一个对应的帮手可以了(jin)。这栯然类多了(jin)一些,但是W合“开Q闭”原则,书上UC为“工厂方法模式”。如图:(x)
假如Client现在要用一个小学生Q代码如下:(x)
在这里还是要两点Q?/FONT>
n 虽然实际?/SPAN>Client的确使用?jin)一个小学生对象Q?/SPAN>Small_StudentQ,但这?/SPAN>Client也认为它?yu)?/SPAN>Student对象Q这里一定要?/SPAN>Student接口来隐藏它的具体类?/SPAN>
n 另外Q却不需要用Student_Factoryq个接口来隐藏它的具体类Q因为,Client实际是通过“选择它的具体cZ这招儿来“选择创徏的学生类型”。这里的Student_Factory更多的功能不是“隐藏”具体类Q而是“规范”具体类?/SPAN>
目实践
扯E到此Q该联系我们的项目啦?/SPAN>
׃是做研究生院的项目,其中巨大的需求就是要让同学能在网上提交各U申请单Q申请退学的Q申误{专业的,甌复学的,甌保留学籍的,除了(jin)甌x友的外,应有有?/SPAN> 对于q些单子Q用最最基本OO思维Q根据共性个性分析方式,抽象Z个申请单接口Q和若干的具体类?/SPAN>
当然Q除?jin)概念上感性上d以外Q在目中它们也要“真”的有巨大的共性才行,如都要提交,修改Q删除,审核Q打印等功能?/SPAN>
靠,既然都这样了(jin)Q肯定就用一接口规定它了(jin)?/SPAN>
惛_q里Q加上有?jin)上面的思考,不用说了(jin)Q就用工厂方法模式啦?BR>
图中Ent_Shift是甌单接口。等于前面分析的Student接口。还可以看到有很多具体类Q前面例子中是代表各U学生,q里是代表各种甌单?/SPAN>
当然Q这里还有很多工厂,也就是前面一直叫的“帮手”?BR>
Bean_Shift是工厂接口Q相当于前面?/SPAN>Student_Factory接口。还有很多的具体cd是生产各U申请单的工厂类?/SPAN>
下面是使用“申请单工厂Ҏ(gu)模式”的一D客L(fng)代码Q?BR>
升华
个h比较同意?/SPAN>Design Pattern Explained》中作者讲的,要用好很多的模式Q其中都有一个思\Q就是用接口或抽象类来隐藏子cȝ不同?/SPAN>
我每当看到这Ӟ老是?x)被一U思\困扰――?/SPAN>new只能new具体cdQ这咋能隐藏呢,q隐藏还有什么用呢?”?/SPAN>
作者仿?jng)也曄有过我的q个?/SPAN>B苦恼Q它的解x法就是:(x)Ҏ(gu)在用对象的时候,特别是设计阶D,量不去惛_象是在那里被new的。他认ؓ(f)Q反正有?jin)工厂模式后Q你L办法把他?/SPAN>new出来的?/SPAN>
所以,我用?jin)工厂模式后更发的启发是Q以后设计的时候不要想一?/SPAN>Client怎么创徏一个对象,管攑ֿ(j)大胆的先l箋惻I直接使用好?jin)。反正最后我q有工厂模式呢?/SPAN>
因此俺的副标题才是?/SPAN>Ignore how they were created”,呵呵?BR> MARCO ZHANG 2006q??6?:52:10