2009年4月10日星期五

JavaDesign_029:Java设计模式五诫(摘录+整理)

1. 不要盲目崇拜设计模式。
2. 不要滥用设计模式。
3. 要完全理解问题的症结所在。
4. 要完全理解每一个设计模式的用意。
5. 要理论结合实际,不要死班硬套。

2009年4月9日星期四

JavaDesign_028:迭代模式 Iterator(摘录+整理)

1. 特点
(1)访问一个聚集中的元素而不必暴露聚集的内部。
(2)将迭代逻辑与聚集本身“解耦

2. 优点
(1)从一种聚集改变成另一种聚集,不需要修改客户端代码。
(2)改变迭代方式很容易,客户端不需要修改代码

3. 缺点
(1)客户端容易误以为迭代是按照顺序进行的。实际情况取决于迭代逻辑,不一定与客户端认为的相一致。
(2)聚集元素没有特征,客户端必须知道是何种类型。
4. 代码架构
(1)抽象迭代子:定义遍历元素的接口。
(2)具体迭代子:实现遍历元素的接口。
(3)抽象聚集类:定义创建迭代子的接口。

(4)具体聚集类:实现迭代子的接口,返回一个迭代子实例。

5. Java中对命令模式的应用
(1)实现Collection接口的类。
6. 典型应用场景
(1)两个警察的购物篮:用不同的方式迭代不同的聚集。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_027:不变模式 Immutable(摘录+整理)

1. 特点
(1)一个对象被创建之后就不再改变。

2. 优点(1)因为不能修改对象的状态,因此不变对象比可变对象更加容易维护。
(2)因为不能修改对象的状态,因此不变对象是线程安全的。

3. 缺点(1)因为不能修改对象的状态,因此如果不得不改变对象,只好创建一个新对象。

4. 代码架构(1)弱不变模式类的实例都不可改变。子类的实例可以改变。
  • 所有的属性都应当是私有的。
  • 引用到的其它对象如果是可变的,应当在不变对象内部初始化。
  • (接上)如果只能在外部初始化,再传入时,“克隆”一份新的。
(2)强不变模式:类及子类的实例都不可改变。
  • 满足所有弱不变的模式。
  • 所有的方法都是final的(子类无法置换)。
  • 类本身是final的(不可能有子类)
5. Java中对命令模式的应用
(1)String。
(2)封装类:Long、Integer......
6. “不变(Immutable)”与"只读(Read Only)"的区别不变”即不发生改变,“只读”可能发生改变(因为其它变量的改变而改变)。
比如一个人的生日是“不变”
的,一个人的年龄是“只读”的,生日一旦“创建”就不可改变,年龄则一年年变化,但是”只读“的。
7. 典型应用场景(1)复数类
参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_026:访问者模式 Visitor(摘录+整理)

1. 特点
(1)把数据结构和作用于结构上的操作“解耦”。
(2)数据结构相对稳定(可以有多个),而操作可以独立地演化。

2. 优点
(1)增加新的操作变得很容易。
(2)访问不同类型的等级结构。

3. 代码架构
(1)抽象访问者:声明一个或多个访问操作。
(2)具体访问者:继承抽象访问类,实现所有访问操作。
(3)抽象节点类:声明一个accept()方法,接受抽象访问者作为参数。

(4)具体节点类:实现accept()方法。
(5)结构对象类:遍历结构中的所有元素。

4. 典型应用场景
(1)同属于Collection的不同聚集上的不同操作。
(2)电脑专卖店(整机、配件)。树型结构的产品相对固定、两种访问者:价格和库存。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_025:调停者模式 Meditaor(摘录+整理)

1. 特点
(1)用一个中介对象来封装一系列关于对象交互行为
(2)把对象之间的交互行为从网状结构变成星型结构。

2. 优点
(1)需要增加或减少对象时,只需要修改中介对象,其它对象不变。
(2)对象更容易被复用。

3. 代码架构
(1)抽象调停者:定义所有抽象接口以及interpret()方法。
(2)具体调停者:继承抽象调停者类。
(3)抽象同事类:只关联抽象调停者,不知道其它的同事对象。

(4)具体同事类:继承抽象同事类。

4. 误用调停者模式的情况
(1)责任划分混乱。此时,应当首先把每个同事类的责任理清楚,而不是着急使用调停者模式。
(2)尽量不要设计“数据类”和“纯方法类“。因为封装是对行为以及行为所涉及的状态的封装。

5. 典型应用场景
(1)中国加入WTO。商务运作可以交给WTO组织,而不需要直接面对各个国家的商务条款。
(2)聊天应用中的MessageMediator,专门负责request/reponse之间任务的调节。
(3)其它信息传递应用。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_024:解释器模式 Interpreter(摘录+整理)

1. 特点
(1)定义一个语言的文法,文法即语言元素组合的规则集。
(2)定义一个解释器,用来解释该语言中的句子。
(3)效率不是主要关心的问题。

2. 代码架构
(1)抽象表达式类:定义所有抽象接口以及interpret()方法。
(2)终结符表达式类:实现抽象表达式类。每一个终结符都对应一个具体的终结符表达式。
(3)非终结符表达式类:实现抽象表达式类。

(4)环境类:提供全局信息。

3. 典型应用场景
(1)匹配模式搜寻字符串。与其为每一个匹配模式创建一个特定的算法,不如创建一个一般性的算法来处理各种表达式。
(2)宏语言。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_023:策略模式 Strategy(摘录+整理)

1. 特点
(1)定义一系列的算法,把这些算法封装成一个个单独的类。
(2)这些算法类有共同的接口,使得彼此可以互相替换。
(3)运行时某一时刻只能使某一算法,使用哪一个,由客户端决定。

2. 代码架构(1)环境类:聚合抽象策略类,即持有一个抽象策略类的实例。
(2)抽象策略(接口或抽象类,视情况而定)。
(3)具体策略类,继承或实现抽象策略类。

3. Java中对命令模式的应用
(1)AWT库中的LayoutManager。
(2)Swing库中的Border。
4. 与装饰模式的区别(1)装饰模式是在不改变接口的情况下,增强对象的功能;策略模式是在不改变接口的情况下,使不同的算法可以互相替换。
(2)同时需要使用多个算法的情形不适用策略模式,应该考虑装饰模式。
比如有些折扣算法比较特殊:要求不管使用哪种折扣算法,折扣总金额不能超过1000元。
这就需要先用不同的算法算出折扣,看看是否超过1000元。


5. 典型应用场景(1)以不同的格式保存文件(2)以不同的算法压缩文件(3)以不同的算法截获图象(4)以不同的排序算法排序:二元排序、冒泡排序、堆栈排序、快速排序、基数排序。
(5)以不同的格式输出同样数据的图形:曲线图、柱状图、饼状图。
(6)网上购物中不同产品的不同的计算折扣算法。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_022:状态模式 State(摘录+整理)

1. 特点
(1)对象的行为取决于对象的状态属性。
(2)对象的状态在不断地转移。

2. 优点(1)可以很容易地增加新的状态和行为。

3. 缺点(1)造成大量的小的状态类。

4 代码架构(1)抽象状态角色。定义有哪些行为。
(2)
具体状态角色。实现行为。根据需要,状态管理器当作参数传入。
(3)状态管理器(环境)角色。聚合关系包含抽象状态角色。

4.1 进一步思考:谁来定义状态的变化?
(1)如果转换条件固定,应当由状态管理器来定义。(曲子存在编钟里)(2)如果转换条件比较灵活,应当由具体状态角色来决定下一个状态是哪个状态。(曲子分散存在每一个钟里)
(3)交由外部系统来决定。(乐师来决定演奏曲目,现场击打编钟)

4.2 进一步思考:谁来管理状态的生命周期(创建/销毁)?
(1)动态地创建,用多少创建多少。
(2)事先全部创建好。

5. 典型应用场景(1)曾侯乙编钟。击打一只只钟时,编钟的状态从一只钟过渡到另一只钟,其声音(即行为)从一只钟过渡到另一只钟。
(2)状态的切换:A->B->C->D->A,并且还需要逆向状态D->C->B->A->D
(3)代码重构:多重条件转移语句,每个分支代码很多,逻辑复杂,不利于维护。重构后,可以让每个分支生成一个状态类,各自独立地演化。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_021:命令模式 Command(摘录+整理)

1. 特点
(1)把发出命令的责任和执行命令的责任分开。
(2)每个命令都被封装成一个类。

2. 把“每个命令都被封装成一个类我能理解,但为什么不让命令的发出方直接执行命令?
一般情况下,当然可以这样做。但增加一个命令执行方,除了出于“解耦”命令的发出方和命令之外,还因为考虑到以下情况:
(1)宏命令:记录多个命令组成一个宏。宏命令也是命令。(2)Undo 与 Redo。的执行命令前宏命令:记录多个命令组成一个宏。(3)多层的Undo 与 Redo。执行命令前宏命令:记录多个命令组成一个宏。(4)拒绝执行某个命令。(5)排队执行某个命令队列。(命令的发出方可能已经不存在了,但命令仍然“活着
(6)记录执行过的重要命令到日志。

3. 代码架构(1)命令执行方类:聚合所有命令,即含有所有命令的实例。
(2)抽象命令(接口或抽象类,在这里一般用接口)。
(3)具体命令,继承或实现抽象命令类。

4. Java中对命令模式的应用
(1)AWT库中的事件处理。
5. 典型应用场景(1)录音机。录音机有Play、Stop等按键,要使用录音机,用户只需要按下不同的按键。(2)界面中的菜单项。
参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_020:责任链模式 Chain of Responsiblity(摘录+整理)

1. 特点
(1)很多对象组成一根“链条(上家包含下家的引用)
(2)请求在这个“链条”上传递,请求的发出者并不知道“链条”上的哪个对象会处理请求。

2. 缺点(1)
(2)
(3)

3. 代码架构(1)抽象处理者。用聚合关系包含对下家的引用。
(2)
具体处理者处理请求或将请求传给下家。
(3)请求对象。根据请求的复杂情况,可以把请求包装成一个对象。

4. Java中对观察者模式的应用
(1)AWT 1.0 库中的事件处理(构件处理GUI事件或将事件传递给上级容器)。
缺点是事件浮升机制会导致事件处理比较慢;而且鼠标事件成灾。
AWT 2.0 库已改成使用观察者模式。
5. 典型应用场景(1)击鼓传花。
(2)把 EDI 转换成 XML。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_019:观察者模式 Observer(摘录+整理)

1. 特点
(1)被观察者的状态做出改变时,通知所有的观察者。
(2)被观察者与观察者之间是“抽象耦合”。

2. 缺点(1)如果观察者过多,通知到每一个观察者可能花费时间较多。(2)如果(1)的情况确实,可以考虑使用异步通知,但需要保证自恰性。
(3)如果被观察者之间有循环依赖的话,可能会发生死循环。

3. 代码架构(1)抽象被观察者。包含所有观察者的聚集以及相关操作。
(2)
具体被观察者当状态发生改变时,通知所有观察者。这里要使用“保护性拷贝”,防止调用者修改聚集。
(3)抽象观察者。为所有具体观察者定义一个接口。
(4)具体观察者。实现update()方法逻辑。

4. Java中对观察者模式的支持与应用
(1)被观察者:Obervable抽象类。观察者:Observer接口。默认的通知顺序是按照登记次序的相反次序,但Obervable的子类可以修改这一次序。
(2)AWT库中的事件处理。
(3)Swing的定时器。

5. 典型应用场景(1)网店有新品推出、打折等活动时,自动通知会员。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_018:备忘录模式 Memeto(摘录+整理)

1. 特点
(1)将对象的所有时刻的状态信息保存在对象以外的地方。
(2)需要获得对象某一时刻的状态信息时,必须要由该对象自己获取。

2. 缺点(1)对象的状态信息保存过多,消耗资源。

3. 代码架构(1)备忘录角色。将发起人对象的状态存储起来,并保护其内容不被其它对象“偷窥”。
(2)发起人角色。创建备忘录对象,并把信息存储到备忘录中。

(3)负责人角色。负责保存备忘录对象,但不能“偷窥”内容。
4. 典型应用场景(1)用户输入数据:填写表格时,错误数据不应该导致正确数据重新填写。(2)Cookie的应用
(3)视窗Reset功能。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_017:模版方法模式 Template Method(摘录+整理)

1. 特点
(1)父类定义的顶级逻辑(模版方法)具有绝对的“权威性”,不可改变。
(2)子类可以置换掉父类的可变逻辑(基本方法,但不可以改变父类定义的顶级逻辑。
(3)顶级逻辑(模版方法)调用可变逻辑(基本方法)。

2. 代码架构(1)定义一个抽象类,其中包含抽象基本方法(强制子类必须实现,方法不宜太多),以及一个具体的模版方法,模版方法调用基本方法。
(2)定义
该抽象类的子类,实现所有抽象基本方法。不同的子类,有不同的实现方法。
(3)基本方法的命名一般为doXXX()。
(4)基本方法也可以不是抽象的,可以存放所有子类共同的逻辑。

3. Java中对模版方法模式的应用
(1)模版方法模式本身就利用了Java中的抽象类的继承特点来实现的。(2)HttpServlet类。模版方法:service(),基本方法:7个doXX()。(3)AbstracTableModel类。(4)AbstracListModel类。
4. 典型应用场景(1)为不同的账户(活期、定期)计算利息(账户类型、利息率、利息)。(2)运行某Benchmark 算法多次,取平均值。Benchmark 算法交给子类实现。
(3)重构代码:用多态性取代条件转移。原来不同的几个方法,经过分析发现功能其实相同,只是实现不同;遂改成同名方法,由不同的子类实现。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_016:享元模式 Flyweight(摘录+整理)

1. 特点
(1)共享大量内容相同的细粒度对象,减少内存开销。(2)享元对象包含内蕴状态和外蕴状态,内蕴状态可以共享,外蕴状态不可以共享。(3)外蕴状态由客户端保存,外蕴状态无法影响内蕴状态。
举例来说:文本编辑器中的字体,一个字体就是一个享元,内蕴状态就是这个字本身,字体的字模风格和所在位置就是外蕴状态。


2. 代码架构(1)抽象享元类,含商业方法,外蕴状态作为参数传入。(2)具体享元类继承抽象享元类,构造函数参数为内蕴状态
(3)享元工厂,一般为单例模式,即只能由享元工厂创建和管理享元,保证享元被适当地共享。工厂方法参数为内蕴状态

3. Java中对享元模式的应用
(1)String 类,不变对象,一旦创建出来就无法改变。
对于内容相同的两个字符串,JVM只创建一个String对象给这两个引用。
4. 典型应用场景(1)文本编辑器中的字体。(2)CD对象中的演唱者(一个演唱者可以出版多个专辑CD)。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_015:桥梁模式 Bridge(摘录+整理)

1. 特点
(1)将抽象化和实现化解耦,使得二者可以独立地变化,是动态的。(2)实现化的改变对客户端透明,即使用者感觉不出后的变化。

2. 代码架构(1)定义抽象类,抽象子类。(2)抽象类中聚合实现化类,即含有实现化类的实例,并且将商业方法委派给实现化类中的对应方法。
(3)定义实现化类接口,实现化具体类

3. 典型应用场景(1)咖啡(按容量分为大杯、中杯;按加奶分为加奶、不加奶)。以后可能会有小杯,加糖不加糖,等等。如果全部用子类继承实现,组合太多,不太不现实。不如以咖啡大中小杯为抽象化类,加糖、加奶为实现化类。
(2)AWT的Peer架构。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_014:装饰模式 Decorator(摘录+整理)

1. 特点
(1)动态地扩展或增强对象的功能。(2)接口保持不变,即使用者感觉不出装饰前后的变化。
(3)装饰模式可以嵌套。

2. 代码架构(1)定义Component接口(也可用抽象类,视情况而定)。(2)被装饰类Decoratee和装饰类Decorator都实现了Component接口。(3)装饰类Decorator关联被装饰类Decoratee,即含有被装饰类Decoratee实例。
(4)装饰类Decorator的实现方法委派给被装饰类Decoratee,但功能有所增强。
(5)如果需要,可以把装饰类Decorator定义为抽象类,由子装饰类类继承。

3. 与继承方式实现功能拓展的区别
(1)虽然我们通常使用继承来实现功能的拓展,但如果功能的种类很繁多,那么势必要用很多的子类。而且使用继承方式实现功能拓展,必须事先预知要拓展哪些功能,是静态的、编译时就确定了的。
而装饰模式是
由客户端动态决定加入功能的方式和时机,即在运行期间决定何时增加何种功能。
(2)如果新功能是一些基本功能的排列组合,使用继承方式来实现不太现实,因为排列组合的结果太多。
不如使用装饰模式,让使用者自己决定
排列组合哪些基本功能构成一个新功能。

4. Java中对合成模式的应用
(1)IO库中的BufferedReader类。
FileReader fr = new FileReader(filename);
BufferedReader br = new BufferedReader(fr);


5. 典型应用场景(1)发票打印使用不同的表头和表尾
(2)论坛的信息过滤功能。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_013:合成模式 Composite(摘录+整理)

1. 特点
(1)将对象以树结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

2. 两种代码架构(1)透明架构
针对树型结构中所有的节点都有可能是树枝,比如
论坛中的帖子。
定义Component接口(也可用抽象类,视情况而定),树枝Composite和树叶Leaf都实现该接口,聚集管理定义在Component接口中。
优点:增加新节点很容易。树枝和树叶接口完全一致,使用者可以同等对待。
缺点:使用者有可能错误地在树叶上调用聚集方法,运行时报错。
(2)安全架构针对树型结构中有的节点是树叶,比如文件系统(目录是树枝,文件是树叶)。
定义Component接口(也可用抽象类,视情况而定),树枝Composite和树叶Leaf都实现该接口,聚集管理定义在树枝中。
优点:增加新节点很容易。避免使用者错误地在树叶上调用聚集方法,编译时报错。
缺点:
树枝和树叶接口不完全一致,使用者需要区别对待,即使用前要判断该节点是树枝还是树叶

3. 进一步思考,如何实现遍历父节点(从下向上)?(1)在字节点中定义父节点的引用。(2)增加删除字节点时,修改父节点的引用。

4. Java中对合成模式的应用
(1)AWT库中的Container类和Component类。
Container类继承Component类,Component类关联Container类
其它构件如Button、Checkbox也继承Component类。聚集管理定义在Container类中,是安全架构地实现方式。

5. 典型应用场景(1)文件系统。(根目录、子目录、文件)
(2)论坛中的帖子。(根帖、回帖、回帖的回帖(3)绘图。(复杂的图形都是由简单的图形合成而成的

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_012:适配器模式 Adapter(摘录+整理)

1. 特点
(1)把某个类的接口(Adaptee 被适配者)变成客户端期待的另一种接口Adaptor 适配器从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。

2. 两种代码架构
(1)Adapter类继承Adaptee类,同时实现客户端期待的新接口。优点:可以置换Adaptee的方法。
缺点:无法适配Adaptee的子类。
(2)Adapter类关联Adaptee类,即在Adapter类中有类型为Adaptee的实例变量,同时实现客户端期待的新接口。优点:可以适配Adaptee的子类。
缺点:
无法置换Adaptee的方法(可以Adaptee的子类置换,然后适配子类)。

3. Java中对适配器模式的应用
(1)事件监听器适配器类
(2)缺省适配器类:必须让某个类实现某一个接口,但这个类又用不到接口中规定的所有方法。解决办法:用一个抽象类实现该接口(每个方法实现都是空方法),该抽象类为缺省适配器,真正的适配器类继承缺省适配器,从而可以只实现需要实现的方法。

4. 与代理模式的区别
适配器模式改变对象的接口,代理模式不改变所代理对象的接口。

5. 典型应用场景(1)变压器。(美国生活电压110v,中国220v)
(2)JDBC。
参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

2009年4月8日星期三

JavaDesign_011:代理模式 Proxy(摘录+整理)

1. 特点
(1)为某个对象提供一个代理对象,要访问这个对象,必须通过代理对象,不可以直接访问。
(2)不可以直接访问的原因要么是这个对象不允许直接访问(比如先要进行权限检查);要么是这个对象无法直接访问(比如没有提供一些功能)。

2. 代理的种类
(1)远程代理
隐藏网络细节,使用者感觉不到网络的存在(仿佛是本地调用),代理承担了所有网络通信工作。

(2)虚拟代理
比如某个文档中有个大图片,为了能够迅速地打开文档,在大图片装载完成之前,在其位置用一个图片Proxy来代替。
(3)Copy-on-Write 代理比如某个耗时操作要遍历一个很大的Collection,在此过程中很可能被其它对象修改,而如果使用锁机制,则其它对象均不可修改此Collection。此时,可以“克隆”该Collection供耗时操作使用,不过该“克隆”将延迟到其它对象修改了这个Collection才开始,否则直接对原Collection进行耗时操作。
(4)保护代理
在运行时对调用真实对象的用户的权限进行检查,通过后才可以调用真实的对象。
(5)Cache 代理(6)防火墙代理(7)同步代理(8)智能引用代理
调用真实对象时,做些“内部处理”,比如计数等。

3. 代码架构(1)抽象类或接口
(2)真实类。继承抽象类或实现接口。
(3)代理类。继承抽象类或实现接口。含有真实类的引用。在调用真实类的方法之前、之后都要执行某个操作。
4. Java对代理模式的支持(1)java.lang.reflect.Proxy 运行时创建代理对象。
(2)java.lang.reflect.InvocationHandler 对原对象的方法调用会首先分派给调用处理器,在invoke()方法中截获
(3)java.lang.reflect.Method 调用原对象的方法

5. 典型应用场景(1)股票查询系统。(保护代理:根据权限访问;智能引用代理:按查询次数收费)
(2)延迟加载大型图片。(虚拟代理:图片位置显示“正在加载...”,同时用另一个线程加载图片,加载完毕后,把“正在加载...”替换为图片)
此案例中的大型图片可以延伸为大型软件模块,道理是一样的。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

2009年4月7日星期二

JavaDesign_010:门面模式 Facade(摘录+整理)

1. 特点
(1)把一个复杂的子系统功能提炼成一个高层次的简单接口。(2)外部系统只与这个高层次的接口打交道。
(3)这个高层次的接口只能提供子系统中已有的功能,不能提供子系统没有的功能。
(4)一般一个子系统只对应一个门面类,如果可以,该门面类可以做成单例类。
2. 优点
(1)子系统易使用性提高。
(2)子系统独立性和可移植性提高。

3. 典型应用场景
(1)医院系统(挂号、门诊、划价、化验、收费、取药),设立接待员。
(2)保安系统(录像机、电灯、遥感器、警报器),设立安全总控台

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

2009年4月6日星期一

JavaDesign_009:原型模式 Prototype(摘录+整理)

1. 特点
(1)根据一个对象的原型创建另外一个对象,并且完全copy原对象的所有属性,即克隆。

2. 关于clone()方法和
Cloneable接口
(1)clone()方法是java.lang.Object的一个protected 方法。
(2)Cloneable是一个标识接口。
(3)java.lang.Object并没有实现Cloneable这个标识接口。
(4) 如果调用某类的clone()方法,而该类没有实现Cloneable这个标识接口,会抛出CloneNotSupportedException。

3. 代码架构
(1)如果是接口
public interface Prototype extends Cloneable{
Prototype clone();
}
(2)如果是抽象类public abstract class AbstractPrototype implements Cloneable {
 public Object clone() {
  Object object = null;
  try {
  object = super.clone();
  } catch (CloneNotSupportedException exception) {
   System.err.println("
Abstract
Prototype is not Cloneable");
  }
  return object;
  }
}
4. clone()方法的实现必须满足3个条件
(1)x.clone() != x 。
(2)x.clone().getClass() == x.getClass() 。
(3)x.clone().equals(x) == true 。
注意,第3条涉及到equals()方法的实现,而equals()方法的实现又涉及到hashCode()方法的实现。
5. 与工厂模式的区别

6. 典型应用场景
参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏
3.
《Effective Java中文版》 潘爱民 译

2009年4月5日星期日

JavaDesign_008:建造模式 Builder(摘录+整理)

1. 特点
(1)需要创建的对象内部构造十分复杂。
(2)对象的属性之间有依赖关系,如一个属性必须在另一个属性赋值后才能赋值。
(3)对象的某些属性十分重要,如果没有赋值,产品无法使用。
(4)创建的对象的过程中,还要使用其它对象,这些对象不易得到。
如果满足前四条,则非常适用建造模式。

2. 优点
(1)使用者无需关心产品有哪些零件,是如何生产出来的。
(2)产品零件的生产过程和产品的装配流程分开,达到彼此“解耦”目的。
因为同样的零件,不同的装配流程可能生产出不同的产品,比如变形金刚既可以变成汽车,也可以变成机器人。

3. 代码架构
(1)Builder
public interface Builder {

  void buildPartA();
  void buildPartB();
  void buildPartC();

  //返回最后的成品,装配过程不在这里实现
  Product getResult();
}

public class ConcreteBuilder implements Builder {

  Part partA, partB, partC;
  public void buildPartA() {};
  public void buildPartB() {};
  public void buildPartC() {};
  public Product getResult() {};
}

(2)Director
public class Director {

  private Builder builder;

  public Director( Builder builder ) {
    this.builder = builder;
  }
  
// 装配流程在这里实现
  public void construct() {
    builder.buildPartA();
    builder.buildPartB();
    builder.buildPartC();
  }
}

(3)Client
Builder builder = new ConcreteBuilder();
Director director = new Director( builder );
director.construct();
Product product = builder.getResult();

4. 与工厂模式的区别
通过建造模式生产的对象是一个完整的最终产品,而通过工厂模式生产的对象可能是一个完整的产品,也可能是一个零部件。
所以,如果你的产品特别复杂,可以用“建造模式 + 工厂模式”:建造模式组装产品,工厂模式生产零部件。

5. 典型应用场景
(1)收发邮件。
(2)汽车制造。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

2009年4月4日星期六

JavaDesign_007:多例模式 Multition(摘录+整理)

1. 特点
(1)一个类可以有多个实例存在。
(2)只能由该类负责创建多个实例。
(3)只能由该类负责提供多个实例。

2. 有上限多例模式和无上限多例模式
(1)有上限多例模式:骰子游戏
(2)无上限多例模式:由于不知道要创建多少个实例,必须用聚集管理所有的实例。
但与单例模式中管理聚集不同,在无上限多例模式中,聚集用来登记和管理多例自身的实例。

4. 与单例模式一样,多例模式在以下情况时可能会出现状态不一致的情况
(1)跨多个JVM的分布式应用。
(2)同一个JVM中多个类加载器。

5. 典型应用场景
(1)骰子游戏。
(2)多语言支持。每种语言对应一个ResourceBundle,保存在一个HashMap之中。
(3)数据库序列生成器(多个)。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

2009年4月3日星期五

JavaDesign_006:单例模式 Singleton(摘录+整理)

1. 特点
(1)一个类只能有一个实例存在。
(2)只能由该类负责创建该唯一实例。
(3)只能由该类负责提供该唯一实例。

2. 两种实现单例模式的代码结构
(1)饿汉式单例类:在加载类时,唯一实例已经被创建出来了。
public class Singleton {
 private static final Singleton instance = new Singleton();

// 私有的构造函数
private Singleton() {}

 // 静态工厂方法
 public static Singleton getInstance() {
  return instance;   
 }
}

(2)懒汉式单例类:在第一次使用时才创建唯一实例。
public class Singleton {
 private static Singleton instance = null;


 // 静态工厂方法,注意使用了synchronized
 public static synchronized Singleton getInstance() {  
  if (instance==null)
    instance=new Singleton();
  return instance;   
}
}

两种方式比较:
从资源利用效率上来看,懒汉式比饿汉式要好些;
从响应速度上来看,饿汉式比要懒汉式好些;
特别是对于初始化时间较长的资源管理器来说,懒汉式容易引起多线程竞争。
因此,出于安全性考虑,一般使用饿汉式单例模式。

4. 单例模式在以下情况时可能会出现状态不一致的情况,即不能保证唯一实例
(1)跨多个JVM的分布式应用。比如,某个EJB在其JVM中调用了单例类,另一个EJB在其JVM中也调用了单例类。
(2)同一个JVM中多个类加载器。比如,多个Servlet引擎。

5. 典型应用场景
(1)资源管理器。
(2)计数器。
(3)数据库序列生成器。
(4)邮件服务器清单。该清单用聚集(Vector)表示,用单例模式管理该聚集。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_005:抽象工厂模式 Abstract Factory(摘录+整理)

1. 特点
(1)工厂类变成了抽象工厂(
抽象类或接口),不再负责“生产“具体产品,而是把这个工作交给了具体工厂子类去做(这一点与工厂方法模式相同)
(2)所有的产品之间是有关联的,构成一个产品族,产品族中包含不同的抽象产品类或产品接口(3)一个具体工厂类负责“生产”对应的产品族中的所有产品
(3)具体产品类继承抽象产品类或实现产品接口。(这一点与简单工厂模式相同)
(4)每个具体工厂类的工厂方法有多个,每一个对应不同的抽象产品类或产品接口,及其对应的所有具体产品类。

2. 优点
(1)产品使用者无需“生产”产品,只需“消费”产品。
(2)当需要增加产品时,产品使用者代码无需改变
(3)需要增加一个产品族时,只需要增加这个产品族的相关类以及对应的具体工厂子类,其它产品类和工厂类不受影响。
注:
(1)(2)是所有工厂模式的共同的优点。

3. 缺点
1)工厂方法是非静态的,产品使用者必须先创建(拥有)该工厂实例。
4. 典型应用场景
1)不同平台的视窗构件(按钮、文本...)。
2)苹果机和PC机的硬件构件(CPU、内存、...)。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

2009年4月2日星期四

JavaDesign_004:工厂方法模式 Factory Method (摘录+整理)

1. 特点
(1)工厂类变成了抽象工厂(抽象类或接口),不再负责“生产“具体产品,而是把这个工作交给了具体工厂子类去做。
(2)一个具体工厂类对应一个具体产品类
(3)具体产品类继承抽象产品类或实现产品接口。(这一点与简单工厂模式相同)
(4)抽象产品类或产品接口只有一个,具体产品类全部继承抽象产品类或实现产品接口。(这一点与简单工厂模式相同)
(5)每个具体工厂类的工厂方法可以有多个,但返回类型都是同一个抽象产品类或产品接口。

2. 优点
(1)产品使用者无需“生产”产品,只需“消费”产品。
(2)当需要增加产品时,产品使用者代码无需改变。
(3)当需要增加具体产品类时,只需要增加这个具体产品类以及对应的具体工厂子类,其它产品类和工厂类不受影响。
注:(1)(2)是所有工厂模式的共同的优点。

3. 缺点
(1)工厂方法是非静态的,产品使用者必须先创建(拥有)该工厂实例。

4. 典型应用场景
(1)不同的DAO工厂。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

2009年4月1日星期三

JavaDesign_003:简单工厂模式 Simple Factory (摘录+整理)

1. 特点
(1)工厂类用静态方法根据业务逻辑“生产“具体产品类。工厂类依赖于具体产品类。
(2)具体产品类继承抽象产品类或实现产品接口。选择哪个,视情况而定。
如果具体产品类之间没有共同的逻辑,那么可以让所有具体产品类实现一个产品接口。
否则,应该让所有具体产品类继承一个抽象产品类,并且把公共逻辑放到抽象产品类中。
(3)抽象产品类或产品接口只有一个,具体产品类全部继承抽象产品类或实现产品接口。
(4)工厂类只有一个
(5)工厂方法可以有多个,但返回类型都是同一个抽象产品类或产品接口。

2. 优点
(1)产品使用者无需“生产”产品,只需“消费”产品。
(2)当需要增加产品时,产品使用者代码无需改变。
(3)工厂方法是静态的,产品使用者可以直接调用。
注:(1)(2)是所有工厂模式的共同的优点。

3. 缺点
(1)工厂方法是静态的,子类无法继承。
(2)当需要增加具体产品类时,工厂代码需要改变。
(3)当具体产品类越来越多时,工厂代码将过于全知全能和臃肿。

4. 典型应用场景
(1)动态类装载器。

问题1:何时使用“继承抽象类”,何时使用“实现接口”?
满足以下条件才可以使用继承:
(1)子类是超类的一个特殊种类。Is-A,NOT Has-A,Has-A是聚合关系。
(2)Java不允许子类有多个超类,所以务必确定该子类将来不会出现这种要求。
(3)子类主要的责任是扩展超类,而不是大量置换(Override)超类的方法,虽然Java支持Override。
(4)能够从一般常识解释该子类和超类的关系。比如,不要为了一时方便,从工具类继承,以获得方法重用。

问题2:使用“继承抽象类”时应该注意的问题?
(1)公共逻辑尽可能地集中到抽象类中,为了复用。
(2)数据对象尽可能地留到具体类中创建,减少资源占用。
用一句话说就是,将行为尽可能地移动到结构的高端,而将状态尽可能地移动到结构的低端。

参考文献:
1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_002:Java 设计模式概览 (摘录+整理)

目前,公认的Java设计模式一共有26个,分成三个大类。

1. 创建模式:创建对象的智慧(1)简单工厂模式 Simple Factory
(2)工厂方法模式 Factory Method
(3)抽象工厂模式 Abstract Factory
(4)单例模式 Singleton
(5)多例模式 Multition
(6)建造模式 Builder
(7)原型模式 Prototype

2. 结构模式:解构对象的智慧
(1)门面模式 Facade(2)代理模式 Proxy(3)适配器模式 Adapter(4)合成模式 Composite(5)装饰模式 Decorator(6)桥梁模式 Bridge(7)享元模式 Flyweight

3. 行为模式:操纵对象的智慧
(1)模版方法模式 Template Method(2)备忘录模式 Memeto(3)观察者模式 Observer(4)责任链模式 Chain of Responsiblity(5)命令模式 Command(6)状态模式 State(7)策略模式 Strategy(8)解释器模式 Interpreter
(9)调停者模式 Meditaor
(10)访问者模式 Visitor
(11)不变模式 Immutable
(12)迭代模式 Iterator

接下来,我们就逐个介绍每个模式,建议首先阅读《UML中的类图 Class Diagram 》,有助于理解类之间的关系以及所涉及到的术语。

参考文献:

1. 《设计模式》 板桥里人
2. 《Java与模式》 阎宏

JavaDesign_001:为何要使用设计模式?(摘录+整理)

一言以蔽之,为了提高软件系统的可维护性(Maintainability)可复用性(Reuseability)
在介绍每一个设计模式之前,有必要了解一下所有设计模式背后的原则,即设计原则。

1. 开闭原则 Open-Closed Principle好的软件应该对扩展开放,对修改关闭。
“Software entities should be open for extension,but closed for modifications.”

2. 里氏代换原则 Liskov Substitution Principle任何基类可以出现的地方,子类一定可以出现。
3. 依赖倒转原则 Dependency Inversion Principle要依赖于抽象,不要依赖于实现。
Abstrations should not depned upon details.Details should depend upon abstrations.
要针对接口编程,不要针对实现编程。
Program to an interface,not an implementation.
所谓“倒转
”,是指过去错误软件设计原则:高层次的模块依赖于低层次的模块,抽象的模块依赖于具体的模块。现在要把这个错误纠正过来,“倒转”过来。

4. 接口隔离原则 Interface Segregation Principle
应当为客户提供尽可能小的单独接口,而不是包罗万象的大的接口。

5. 组合/聚合复用原则 Composition/Aggregation Principle尽量使用合成/聚合,而不是继承关系达到复用的目的。

6. 迪米特法则 Law of Demeter
软件的各个模块应当尽可能的相对独立,不与其它模块产生紧耦合关系。

参考文献:

1. 《Java与模式》 阎宏