??xml version="1.0" encoding="utf-8" standalone="yes"?>
定义语言的文?,q且建立一个解释器来解释该语言中的句子.Q后面不用看了)
Interpreterg使用面不是很q?它描qC一个语a解释器是如何构成?在实际应用中,我们可能很少L造一个语a的文?我们q是来简单的了解一?
首先要徏立一个接?用来描述共同的操?
public interface AbstractExpression {
void interpret( Context context );
}
再看看包含解释器之外的一些全局信息
public interface Context { }
AbstractExpression的具体实现分两种:l结W表辑ּ和非l结W表辑ּ:
public class TerminalExpression implements AbstractExpression {
public void interpret( Context context ) { }
}
对于文法中每一条规?非终l符表达式都必须?
public class NonterminalExpression implements AbstractExpression {
private AbstractExpression successor;
public void setSuccessor( AbstractExpression successor ) {
this.successor = successor;
}
public AbstractExpression getSuccessor() {
return successor;
}
public void interpret( Context context ) { }
}
Memento模式相对也比较好理解,我们看下列代?
public class Originator { private int number; private File file = null; public Originator(){} // 创徏一个Memento // 恢复到原始?br /> public void setMemento(Memento m){ }
|
我们再看看Mementoc?
private class Memento implements java.io.Serializable{ private int number; private File file = null; public Memento( Originator o){ number = o.number; } }
|
可见 Memento中保存了Originator中的number和file的? 通过调用Originator中number和file值改变的?通过调用setMemento()Ҏ(gu)可以恢复.
Memento模式的缺Ҏ(gu)耗费?如果内部状态很?再保存一?无意要浪费大量内?
Memento模式在Jsp+Javabean中的应用
在Jsp应用?我们通常有很多表单要求用戯?比如用户注册,需要输入姓名和Email{? 如果一些表用h有填写或者填写错?我们希望在用h"提交Submit"?通过JspE序?发现实有未填写目,则在该项目下U字昄警告或错?同时,q要昄用户刚才已经输入的表?
如下图中 First Name是用户已l输?Last Name没有输入,我们则提C红字警?:
q种技术的实现,是利用了Javabean的scope="request"或scope="session"Ҏ(gu)?也就是Memento模式.
Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-
实例Q?br />l常使用计算机的人恐怕对pȝ备䆾QMementoQ不?x)陌生,当你的Windowspȝq行正常Ӟ对它q行备䆾Q当pȝq行有问题时Q就可以调用备䆾快速的系l恢复,q样可以大量节省重新装pȝ的痛苦,特别是当你缺某一驱动Q或在装pȝ是出C些怪问题时Q犹为痛苦。我xq这U经历的人应该很了解吧,呵呵Q?br />好了Q下面让我们看看q个q程该如何实现吧Q?
1、我们先定义WindowspȝQWindowsSystemQ类Q?br />
public class WindowsSystem {
private String state;
public Memento createMemento() { //创徏备䆾Q保存当前状?br /> return new Memento(state);
}
public void restoreMemento(Memento memento){ //从备份中恢复pȝ
this.state=memento.getState();
}
public String getState(){ //获得状?br /> return this.state;
}
public void setState(String state){ //讄状?br /> this.state=state;
System.out.println("当前pȝ处于"+this.state);
}
}
2、再定义备䆾QMementoQ类Q?br />public class Memento {
private String state;
public Memento(String state) { //备䆾
this.state=state;
}
public String getState(){ //获得状?br /> return this.state;
}
public void setState(String state){ //讄状?br /> this.state=state;
}
}
3、定义用PUserQ类Q?br />public class User {
private Memento memento;
public Memento retrieveMemento() { //恢复pȝ
return this.memento;
}
public void saveMemento(Memento memento){ //保存pȝ
this.memento=memento;
}
}
4、编写测试类Q?br />public class Test {
public static void main(String args[]) {
WindowsSystem Winxp = new WindowsSystem(); //Winxppȝ
User user = new User(); //某一用户
Winxp.setState("好的状?); //Winxp处于好的q行状?br /> user.saveMemento(Winxp.createMemento()); //用户对系l进行备份,W(xu)inxppȝ要生备份文?br /> Winxp.setState("坏的状?); //Winxp处于不好的运行状?br /> Winxp.restoreMemento(user.retrieveMemento()); //用户发恢复命令,pȝq行恢复
System.out.println("当前pȝ处于"+Winxp.getState());
}
}
5、说明:(x)
AQ定义:(x)Memento对象是一个保存另外一个对象内部状态拷贝的对象Q这样以后就可以该对象恢复到原先保存的状态?br />BQMemento模式的用意是在不破坏装的条件下Q将一个对象的状态捕捉住Qƈ外部化,存储hQ从而可以在来合适的时候把q个对象q原到存储v来的状态?br />CQMemento模式所涉及(qing)的角色有三个Q备忘录角色、发起h角色和负责h角色?br />备忘录角色的作用Q?br />Q?Q ?发起h对象的内部状态存储v来,备忘录可以根据发起h对象的判断来军_存储多少发v人对象的内部状态?br />Q?Q ?备忘录可以保护其内容不被发v人对象之外的M对象所d?br />发v色的作用Q?br />Q?Q ?创徏一个含有当前内部状态的备忘录对象?br />Q?Q ?使用备忘录对象存储其内部状态?br />负责色的作用Q?br />Q?Q ?负责保存备忘录对象?br />Q?Q ?不检查备忘录对象的内宏V?br />DQ在本例中,备䆾QMementoQ类是备忘录角色、WindowspȝQWindowsSystemQ类是发起h角色、用PUserQ类是负责h角色。?!--/lxfcn-->
public abstract class Component {
private String name;
public abstract Component addChild(Component leftChild, Component rightChild);
public String getName() {
return name;
}
public void getTreeInfo() {
}
public abstract int getLength();
}
/** Leaf.java **************/
package binarytree;
public class Leaf extends Component {
private String name;
private Component leaf = null;
public Leaf(String name) {
this.name = name;
}
public Component addChild(Component leftChild, Component rightChild) {
return this;
}
public String getName() {
return name;
}
public int getLength() {
return 1;
}
public static void main(String[] args) {
}
}
/** Tree.java **************/
package binarytree;
public class Tree extends Component {
private String name;
private Component leftChild;
private Component rightChild;
public Tree(String name, Component leftChild, Component rightChild) {
this.name = name;
this.leftChild = leftChild;
this.rightChild = rightChild;
}
public Tree(String name) {
this.name = name;
this.leftChild = null;
this.rightChild = null;
}
public Component addChild(Component leftChild, Component rightChild) {
this.leftChild = leftChild;
this.rightChild = rightChild;
return this;
}
public String getName() {
return name;
}
public void getTreeInfo()
// 得到?wi)或叶子的详l信?br /> // 先打印自q名字Q再遍例左孩子,再遍例右孩子
// 如果左孩子或叛_子是?wi),递归调用
{
System.out.println(" this trees name is " + getName());
if (this.leftChild instanceof Leaf) {
System.out.println(getName() + "s left child is "
+ this.leftChild.getName() + ",it is a Leaf");
}
if (this.leftChild instanceof Tree) {
System.out.println(getName() + "s left child is "
+ this.leftChild.getName() + ",it is a Tree");
this.leftChild.getTreeInfo();
}
if (this.leftChild == null) {
System.out.println(getName() + "s left child is a null");
}
if (this.rightChild instanceof Leaf) {
System.out.println(getName() + "s right child is "
+ this.rightChild.getName() + ",it is a Leaf");
}
if (this.rightChild instanceof Tree) {
System.out.println(getName() + "s right child is "
+ this.rightChild.getName() + ",it is a Tree");
this.rightChild.getTreeInfo();
}
if (this.rightChild == null) {
System.out.println(getName() + "s right child is a null");
}
// System.out.println(getName()+"s 高度 ?"+getLength());
}
public int getLength() {
// 比较左孩子或叛_子的高度Q谁大,+1 q回
// I孩子的处理
if (this.leftChild == null) {
if (this.rightChild == null)
return 1;
else
return this.rightChild.getLength() + 1;
} else {
if (this.rightChild == null) {
return this.leftChild.getLength() + 1;
} else {
if ((this.leftChild.getLength()) >= (this.rightChild
.getLength()))
return this.leftChild.getLength() + 1;
else
return this.rightChild.getLength() + 1;
}
}
}
public static void main(String[] args) {
}
}
/** Test.java 试c?**************/
package binarytree;
public class Test {
public Test() {
}
public static void main(String[] args) {
Component tree = new Tree("luopeng");
Component left_child = new Leaf("luopeng1");
Component right_child = new Leaf("luopeng2");
tree = tree.addChild(left_child, right_child);
// tree=tree.addRightChild(right_child);
tree.getTreeInfo();
Component tree1 = new Tree("luopeng2");
tree1.addChild(tree, left_child);
tree1.getTreeInfo();
Component tree2 = new Tree("luopeng3");
tree2.addChild(tree, null);
tree2.getTreeInfo();
Component tree4 = new Tree("luopeng4");
tree4.addChild(null, tree);
tree4.getTreeInfo();
System.out.println(tree4.getName() + "的高度是 " + tree4.getLength());
}
}
Composite比较Ҏ(gu)理解Q想到Composite应该想到树(wi)形结构图。组合体内这些对象都有共同接?当组合体一个对象的Ҏ(gu)被调用执行时QComposite遍?Iterator)整个?wi)Şl构,L同样包含q个Ҏ(gu)的对象ƈ实现调用执行。可以用牵一动百来Ş宏V?/p>
所以Composite模式使用到Iterator模式Q和Chain of Responsibility模式cM?/p>
Composite好处:
1.使客L(fng)调用单,客户端可以一致的使用l合l构或其中单个对象,用户׃必关p自己处理的是单个对象还是整个组合结构,q就化了客户端代码?br />2.更容易在l合体内加入对象部g. 客户端不必因为加入了新的对象部g而更改代码?/p>
如何使用Composite?
首先定义一个接口或抽象c,q是设计模式通用方式了,其他设计模式Ҏ(gu)口内部定义限制不多,Composite却有个规定,那就是要在接口内部定义一个用于访问和理Compositel合体的对象们(或称部gComponentQ?
下面的代码是以抽象类定义Q一般尽量用接口interface,
public abstract class Equipment { private String name; //实h(hun) public abstract double netPrice(); //折扣h public abstract double discountPrice(); //增加部gҎ(gu) public boolean add(Equipment equipment) { return false; } //删除部gҎ(gu) public boolean remove(Equipment equipment) { return false; } //注意q里Q这里就提供一U用于访问组合体cȝ部gҎ(gu)?br /> public Iterator iter() { return null; } public Equipment(final String name) { this.name=name; } } |
抽象cEquipment是Component定义Q代表着l合体类的对象们,Equipment中定义几个共同的Ҏ(gu)?/p>
public class Disk extends Equipment { public Disk(String name) { super(name); } //定义Disk实h(hun)? public double netPrice() { return 1.; } //定义了disk折扣h?.5 Ҏ(gu)?br /> public double discountPrice() { return .5; } } |
Disk是组合体内的一个对象,或称一个部Ӟq个部g是个单独元素( Primitive)?br />q有一U可能是Q一个部件也是一个组合体Q就是说q个部g下面q有'儿子'Q这是树(wi)形结构中通常的情况,应该比较Ҏ(gu)理解。现在我们先要定义这个组合体Q?/p>
abstract class CompositeEquipment extends Equipment //注意q里Q这里就提供用于讉K自己l合体内的部件方法?br /> //上面disk 之所以没有,是因为Disk是个单独(Primitive)的元? |
上面CompositeEquipmentl承了Equipment,同时己里面的对象们提供了外部讉K的方?重蝲了Iterator,Iterator是Java的Collection的一个接口,是Iterator模式的实?一般没必要重蝲Iterator?/font>
我们再看看CompositeEquipment的两个具体类:盘盒Chassis和箱子CabinetQ箱子里面可以放很多东西Q如底板Q电(sh)源盒Q硬盘盒{;盘盒里面可以放一些小讑֤Q如盘 软驱{。无疑这两个都是属于l合体性质的?/p>
public class Chassis extends CompositeEquipment { public Chassis(String name) { super(name); } public double netPrice() { return 1.+super.netPrice(); } public double discountPrice() { return .5+super.discountPrice(); } } public class Cabinet extends CompositeEquipment |
x我们完成了整个Composite模式的架构?/p>
我们可以看看客户端调用Composote代码:
Cabinet cabinet=new Cabinet("Tower");
Chassis chassis=new Chassis("PC Chassis");
//PC Chassis装到Tower?(盘盒装到箱子里)
cabinet.add(chassis);
//一?0GB的硬盘装?PC Chassis (硬盘装到盘盒里)
chassis.add(new Disk("10 GB"));
//调用 netPrice()Ҏ(gu);
System.out.println("netPrice="+cabinet.netPrice());
System.out.println("discountPrice="+cabinet.discountPrice());
上面调用的方法netPrice()或discountPrice()Q实际上Composite使用Iterator遍历了整个树(wi)形结?L同样包含q个Ҏ(gu)的对象ƈ实现调用执行.
Composite是个很y妙体现智慧的模式Q在实际应用中,如果到?wi)Şl构Q我们就可以试是否可以使用q个模式?/p>
以论坛ؓ(f)例,一个版(forum)中有很多帖子(message),q些帖子有原始脓(chung)Q有对原始脓(chung)的回应脓(chung)Q是个典型的?wi)Şl构Q那么当然可以用Composite模式Q那么我们进入Jive中看看,是如何实现的.
Jive解剖
在Jive?ForumThread是ForumMessages的容器container(l合?.也就是说QForumThreadcM我们上例中的 CompositeEquipment.它和messages的关pd图:(x)
[thread]
|- [message]
|- [message]
|- [message]
|- [message]
|- [message]
我们在ForumThread看到如下代码Q?br />
public interface ForumThread { .... public void addMessage(ForumMessage parentMessage, ForumMessage newMessage) throws UnauthorizedException; public void deleteMessage(ForumMessage message) } |
cMCompositeEquipment, 提供用于讉K自己l合体内的部件方? 增加 删除 遍历.
Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-
Composite模式的意图是“将对象l合成树(wi)形结构表C‘整?部分’的层次l构。Composite使得用户对单个对象和l合对象的用更h一致性”?/p>
在Word中我们经怼(x)一些图元进行“组合”,l合以后的图形还可以向简单图元那栯行移动、变形等{操作;除此以外Q在Word中,我们对于一个字W、一个词l、一句话、一个段落,甚至是整文章的操作是相同的Q我们都可以q行剪切、复Ӟq行字体与大的调整Q进行颜色的变换。这些例子都是Composite模式的实例,我们简单的元素l合成复杂的元素Q然后还可以像操作简单元素那h作组合元素?/p>
Composite模式子元素l织成树(wi)型,实际上,l织成图型也没有问题。用hL喜欢l合单元素,一斚wQ用户可以通过q样的组合来q行抽象Q另一斚wQ用户可以通过l合化简J琐的操作。Composite模式在各U可视化~辑软g中应用得最为广泛?/p>
另一使用Composite的经怾子是Java的Swingpȝ。所有的Swinglg都是l承自一个叫做JComponent的接口,因此Q我们对一个JFrame的操作和对一个JButton的操作是一L(fng)。这同时也得,JFrame在管理自q子元素时Q它不需要知道他们是一个JButtonq是一个JPanelQ对它来_(d)q只是一个JComponent?/p>
实现Composite模式的关键是良好设计的接口,Z应该对可能的元素Q简单的、组合的Q进行分析,q设计出通用的操作。尽可能的保证接口操作对所有元素都是有意义的,否则应该将那些只对部分元素有意义的操作下放到子cM?br />
Z么要使用Proxy?
1.授权机制
我们开发一个应用系l时Q用戯求Q何页面都要经q权限控Ӟ最早开发的时候我们常常封装一个权限验证方?/span>,然后在每?/span>jsp或者对应的servlet中增加相关代码,但是用户Ҏ(gu)限的需求往往是多变的Q这样一旦权限验证方法变化(参数变化Q增加方法)Q如果开发的pȝ很庞大的话,有可能你需要修改几百个jsp面或?/span>servlet代码?br />q有我们帔R要判?/span>session是否q期Q如果过期就要重新登陆系l,如果每个面或?/span>servlet都要加判断代码,那也是g比较痛苦的事情?br />如果我们采用代理模式Q增?/span>Proxy对象Q每ơ用戯求必通过proxy对象处理Q由它专门处理相x限控Ӟ一旦权限需求变化了Q只需要修?/span>Proxy对象相关的实现方法?/span>
2.某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.
举例4个具体情?
u 一个对象,比如一q很大的囑փQ需要蝲入的旉很长?
u 一个需要很长时间才可以完成的计结果,q且需要在它计过E中昄中间l果
u 一个存在于q程计算Z的对象,需要通过|络载入q个q程对象则需要很长时_(d)特别是在|络传输高峰期?
u 一个对象只有有限的讉K权限Q代理模?Proxy)可以验证用户的权?
M原则?对于开销很大的对?只有在用它时才创徏,q个原则可以为我们节省很多宝늚Java内存. 所?有些为Java耗费资源内存,我以和程序编制思\也有一定的关系.
单实例:(x)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface AnInterface {
public void doSomething();
}
class AClass implements AnInterface {
public void doSomething() {
System.out.println("Inside Method AClass.doSomething()");
}
}
class SimpleInvocationHandler implements InvocationHandler {
public SimpleInvocationHandler(Object realSubject) {
this.realSubject = realSubject;
}
public Object invoke(Object proxy, Method m, Object[] args) {
Object result = null;
System.out.println("Before Calling " + m.getName());
try {
result = m.invoke(realSubject, args);
} catch (Exception ex) {
System.exit(1);
}
System.out.println("After Calling " + m.getName());
return result;
}
private Object realSubject = null;
}
public class Test {
public static void main(String args[]) {
AnInterface realSubject = new AClass();
AnInterface proxy = (AnInterface) Proxy.newProxyInstance(realSubject
.getClass().getClassLoader(), realSubject.getClass()
.getInterfaces(), new SimpleInvocationHandler(realSubject));
passMeAProxy(proxy);
}
private static void passMeAProxy(AnInterface anInterface) {
anInterface.doSomething();
}
}
4。Proxy模式和Strategy模式
Adapter模式和代理模?Proxy)都是在对象间构造一个简单的层。然而,Adapter模式向对象提供一个不同的接口Q代理模?Proxy)为对象提供相同的接口?
Prototype模式允许一个对象再创徏另外一个可定制的对象,Ҏ(gu)无需知道M如何创徏的细?工作原理?通过一个原型对象传l那个要发动创徏的对象,q个要发动创建的对象通过h原型对象拯它们自己来实施创建?/p>
如何使用?
因ؓ(f)Java中的提供clone()Ҏ(gu)来实现对象的克隆,所以Prototype模式实现一下子变得很简?
以勺子ؓ(f)例:(x)
public abstract class AbstractSpoon implements Cloneable { String spoonName; public void setSpoonName(String spoonName) {this.spoonName = spoonName;} public String getSpoonName() {return this.spoonName;} public Object clone() { Object object = null; try { object = super.clone(); } catch (CloneNotSupportedException exception) { System.err.println("AbstractSpoon is not Cloneable"); } return object; } } |
有个具体实现(ConcretePrototype):
public class SoupSpoon extends AbstractSpoon
|
调用Prototype模式很简?
AbstractSpoon spoon = new SoupSpoon();
AbstractSpoon spoon2 = spoon.clone();
当然也可以结合工厂模式来创徏AbstractSpoon实例?/p>
在Java中Prototype模式变成clone()Ҏ(gu)的用,׃Java的纯z的面向对象Ҏ(gu),使得在Java中用设计模式变得很自然Q两者已l几乎是然一体了。这反映在很多模式上Q如Interator遍历模式?/p>
Builder模式是一步一步创Z个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容可以构建它?用户不知道内部的具体构徏l节.Builder模式是非常类似抽象工厂模?l微的区别大概只有在反复使用中才能体?x)?
Z使用?
是ؓ(f)了将构徏复杂对象?b>q程和它?i>部g解?注意: 是解?b>q程?i>部g.
因ؓ(f)一个复杂的对象,不但有很多大量组成部?如汽?有很多部?车轮 方向?发动有各U小零g{等,部g很多,但远不止q些,如何这些部件装配成一辆汽?q个装配q程也很复杂(需要很好的l装技?,Builder模式是Z部件和l装q程分开.
如何使用?
首先假设一个复杂对象是由多个部件组成的,Builder模式是把复杂对象的创建和部g的创建分别开?分别用BuildercdDirectorcL表示.
首先,需要一个接?它定义如何创建复杂对象的各个部g:
public interface Builder { //创徏部gA 比如创徏汽R车轮 } |
用Director构徏最后的复杂对象,而在上面Builder接口中封装的是如何创Z个个部g(复杂对象是由q些部gl成?,也就是说Director的内Ҏ(gu)如何部件最后组装成成品:
public class Director { private Builder builder; public Director( Builder builder ) { } } |
Builder的具体实现ConcreteBuilder:
通过具体完成接口Builder来构建或装配产品的部?
定义q明它所要创建的是什么具体东?
提供一个可以重新获取品的接口:
public class ConcreteBuilder implements Builder { Part partA, partB, partC; } |
复杂对象:产品Product:
public interface Product { } |
复杂对象的部?
public interface Part { } |
我们看看如何调用Builder模式:
ConcreteBuilder builder = new ConcreteBuilder();
Director director = new Director( builder );
director.construct();
Product product = builder.getResult();
Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q?br />通俗讲解QBuilder模式的理?/strong>
单地_(d)好象我要一座房子住Q可是我不知道怎么盖(单的砌墙Q层ơ较低)Q也不知道怎么栯计(建几个房_(d)几个门好看,层次较高Q, 于是我需要找一帮民工,他们?x)砌墙,q得找个设计师,他知道怎么设计Q我q要保民工听设计师的领|而设计师本n也不q活Q光是下命o(h)Q这里砌一堵墙Q这里砌一扇门Q这h工开始徏设,最后,我可以向民工要房子了。在q个q程中,设计师是什么也没有Q除了他在脑子里的设计和命o(h)Q所以要房子也是跟民工要Q记住了Q?br />
p国内好多企业上erp一P上erpQ首先得找Y件公司呀Q找到Y件公司后QY件公司说Q我只知道怎么写YӞq道怎么实现Q不清楚整个erp的流E。好Q那我们q得找一个咨询公司,好,扑ֈ德勤了,德勤说好Q我要Y件怎么做,软g公司怎么做,我就能保证Y件能Z们提供erppȝ了?br />
此模式是Z让设计和施工解耦,互不q扰?br />
package builder;
public interface Builder
{
public void makeWindow();
public void makeFloor();
public Room getRoom();
}
/*************************************************************/
package builder;
public class Designer {
public Designer() {
}
public void order(Builder builder)
{
builder.makeWindow();
builder.makeFloor();
}
}
/*************************************************************/
package builder;
public class Mingong implements Builder{
private String window="";
private String floor="";
public Mingong() {
}
public void makeWindow(){
window=new String("window");
}
public void makeFloor(){
floor=new String("floor");
}
public Room getRoom()
{
if((!window.equals(""))&&(!floor.equals("")))
{
Room r = new Room();
r.setFloor(floor);
r.setWindow(window);
return r;
}
else return null;
}
}
/*************************************************************/
package builder;
public class Room {
private String window="";
private String floor="";
public Room() {
}
public String getFloor() {
return floor;
}
public void setFloor(String floor) {
this.floor = floor;
}
public String getWindow() {
return window;
}
public void setWindow(String window) {
this.window = window;
}
}
/*************************************************************/
package builder;
public class Client {
public Client() {
}
public static void main(String[] args) {
Builder mingong=new Mingong();
Designer designer=new Designer();
designer.order(mingong);
Room r = mingong.getRoom();
System.out.println(r.getWindow);//?x)输出windowQ表C构建成功?br /> }
}
public class IntegerAdder implements Observer {
private IntegerDataBag bag;
public IntegerAdder( IntegerDataBag bag ) {
this.bag = bag;
bag.addObserver( this );
}
public void update( Subject o ) {
if( o == bag ) {
System.out.println( "The contents of the IntegerDataBag have changed." );
int counter = 0;
Iterator i = bag.iterator();
while( i.hasNext() ) {
Integer integer = ( Integer ) i.next();
counter+=integer.intValue();
}
System.out.println( "The new sum of the integers is: " + counter );
}
}
}
import java.util.Iterator;
public class IntegerPrinter implements Observer {
private IntegerDataBag bag;
public IntegerPrinter( IntegerDataBag bag ) {
this.bag = bag;
bag.addObserver( this );
}
public void update( Subject o ) {
if( o == bag ) {
System.out.println( "The contents of the IntegerDataBag have changed." );
System.out.println( "The new contents of the IntegerDataBag contains:" );
Iterator i = bag.iterator();
while( i.hasNext() ) {
System.out.println( i.next() );
}
}
}
}
IntegerAdder和IntegerPrinter自׃察者增加到IntegerDataBag。当IntegerAdder接收C条更新消息时Q它先统计bag中的LQ然后显C结果。同P当IntegerPrinter接收C条更新消息时Q它打印出bag中的Interger?
下面是一个简单的main()Q它使用了上面的几个c:(x)
public class Driver {
public static void main( String [] args ) {
Integer i1 = new Integer( 1 ); Integer i2 = new Integer( 2 );
Integer i3 = new Integer( 3 ); Integer i4 = new Integer( 4 );
Integer i5 = new Integer( 5 ); Integer i6 = new Integer( 6 );
Integer i7 = new Integer( 7 ); Integer i8 = new Integer( 8 );
Integer i9 = new Integer( 9 );
IntegerDataBag bag = new IntegerDataBag();
bag.add( i1 ); bag.add( i2 ); bag.add( i3 ); bag.add( i4 );
bag.add( i5 ); bag.add( i6 ); bag.add( i7 ); bag.add( i8 );
IntegerAdder adder = new IntegerAdder( bag );
IntegerPrinter printer = new IntegerPrinter( bag );
// adder and printer add themselves to the bag
System.out.println( "About to add another integer to the bag:" );
bag.add( i9 );
System.out.println("");
System.out.println("About to remove an integer from the bag:");
bag.remove( 0 );
}
}
q行mainQ你看刎ͼ(x)
c:\javaworld\java Driver
About to add another integer to the bag:
The contents of the IntegerDataBag have changed.
The new sum of the intergers is: 45
The contents of the IntegerDataBag have changed.
The new contents of the IntegerDataBag contains:
1
2
3
4
5
6
7
8
9
About to remove an integer from the bag:
The contents of the IntegerDataBag have changed.
The new sum of the intergers is: 44
The contents of the IntegerDataBag have changed.
The new contents of the IntegerDataBag contains:
2
3
4
5
6
7
8
9
IntegerDataBag/IntegerAdder/IntegerPrinter是应用Observer模式的一个很单的例子。Java本n有大量用Observer模式的例子:(x)AWT/Swing事g模型Q还有java.util.Observer和java.util.Observable接口{,都是很好的例?br />
我们可以使用一U更为灵zȝҎ(gu)Q就是把文本区嵌入到滚动条中。而这个滚动条的类q当于Ҏ(gu)本区的一?strong>装饰?q个装饰(滚动?必须与被装饰的组?文本?l承自同一个接口,q样Q用户就不必兛_装饰的实玎ͼ因ؓ(f)q对他们来说是透明的。装C(x)用L(fng)h转发 l相应的lg(卌用相关的Ҏ(gu))Qƈ可能在{发的前后做一些额外的动作(如添加滚动条)。通过q种Ҏ(gu)Q我们可以根据组合对文本区嵌套不同的装饰Q从?dL多的功能。这U动态的对对象添加功能的Ҏ(gu)不会(x)引vcȝ爆炸Q也h了更多的灉|性?br /> 以上的方法就?strong>Decorator模式Q它通过l对象添加装饰来动态的d新的功能。如下是Decorator模式的UML图:(x) ![]() Component为组件和装饰的公qc,它定义了子类必须实现的方法?br /> ConcreteComponent是一个具体的lgc,可以通过l它d装饰来增加新的功能?br /> Decorator是所有装饰的公共父类Q它定义了所有装饰必d现的Ҏ(gu)Q同Ӟ它还保存了一个对于Component的引用,以便用L(fng)h转发lC(j)omponentQƈ可能在{发请求前后执行一些附加的动作?br /> ConcreteDecoratorA和ConcreteDecoratorB是具体的装饰Q可以用它们来装饰具体的Component?br /> Java IO包中的Decorator模式 JDK提供的java.io包中使用了Decorator模式来实现对各种输入输出的装。以下将以java.io.OutputStream?qing)其子类ZQ讨Z下Decorator模式在IO中的使用?br /> 首先来看一D는来创建IO的代码Q?br />
q段代码对于使用qJAVA输入输出的人来说再熟?zhn)不过了,我们使用DataOutputStream装了一个FileOutputStream?q是一个典型的Decorator模式的用,FileOutputStream相当于ComponentQDataOutputStream是一?Decorator。将代码Ҏ(gu)如下Q将?x)更?gu)理解Q?br />
׃FileOutputStream和DataOutputStream有公q父类OutputStreamQ因此对对象的装饰对于用h说几乎是透明的。下面就来看看OutputStream?qing)其子类是如何构成Decorator模式的:(x) ![]() OutputStream是一个抽象类Q它是所有输出流的公qc,其源代码如下Q?br />
它定义了write(int b)的抽象方法。这相当于Decorator模式中的ComponentcR?br /> ByteArrayOutputStreamQFileOutputStream ?PipedOutputStream 三个c都直接从OutputStreaml承Q以ByteArrayOutputStreamZQ?br />
它实COutputStream中的write(int b)Ҏ(gu)Q因此我们可以用来创出流的对象,q完成特定格式的输出。它相当于Decorator模式中的ConcreteComponentcR?br /> 接着来看一下FilterOutputStreamQ代码如下:(x)
同样Q它也是从OutputStreaml承。但是,它的构造函数很特别Q需要传递一个OutputStream的引用给它,q且它将保存Ҏ(gu)对象的引 用。而如果没有具体的OutputStream对象存在Q我们将无法创徏FilterOutputStream。由于out既可以是指向 FilterOutputStreamcd的引用,也可以是指向B(ti)yteArrayOutputStream{具体输出流cȝ引用Q因此用多层嵌套的?式,我们可以为ByteArrayOutputStreamd多种装饰。这个FilterOutputStreamcȝ当于Decorator模式中的 Decoratorc,它的write(int b)Ҏ(gu)只是单的调用了传入的的write(int b)Ҏ(gu)Q而没有做更多的处理,因此它本质上没有Ҏ(gu)q行装饰Q所以承它的子cd覆盖此Ҏ(gu)Q以辑ֈ装饰的目的?br /> BufferedOutputStream ?DataOutputStream是FilterOutputStream的两个子c,它们相当于Decorator模式中的 ConcreteDecoratorQƈ对传入的输出做了不同的装饰。以BufferedOutputStreamcMؓ(f)例:(x)
|
Stratrgy应用比较q泛,比如, 公司l营业务变化? 可能有两U实现方?一个是U条曲线,一个是框图(bar),q是两种法,可以使用Strategy实现.
q里以字W串替代Z, 有一个文?我们需要读取后,希望替代其中相应的变?然后输出.关于替代其中变量的方法可能有多种Ҏ(gu),q取决于用户的要?所以我们要准备几套变量字符替代Ҏ(gu).
首先,我们建立一个抽象类RepTempRule 定义一些公用变量和Ҏ(gu):
public abstract class RepTempRule{ protected String oldString=""; public void setOldString(String oldString){ this.oldString=oldString; } protected String newString=""; public String getNewString(){ return newString; } public abstract void replace() throws Exception; } |
在RepTempRule?有一个抽象方法abstract需要承明?q个replace里其实是替代的具体方?
我们现在有两个字W替代方?
1.文本中aaa替代成bbb;
2.文本中aaa替代成ccc;
对应的类分别是RepTempRuleOne RepTempRuleTwo
public class RepTempRuleOne extends RepTempRule{ |
public class RepTempRuleTwo extends RepTempRule{ public void replace() throws Exception{ newString=oldString.replaceFirst("aaa", "ccc") System.out.println("this is replace Two"); } } |
W二步:(x)我们要徏立一个算法解决类Q用来提供客L(fng)可以自由选择法?/p>
public class RepTempRuleSolve {
private RepTempRule strategy; public RepTempRuleSolve(RepTempRule rule){ public String getNewContext(Site site,String oldString) { public void changeAlgorithm(RepTempRule newAlgorithm) { } |
调用如下:
public class test{ ...... public void testReplace(){ //使用W一套替代方?br /> RepTempRuleSolve solver=new RepTempRuleSolve(new RepTempRuleSimple()); //使用W二?/p> solver=new RepTempRuleSolve(new RepTempRuleTwo());
} ..... } |
我们辑ֈ了在q行期间Q可以自由切换算法的目的?/p>
实际整个Strategy的核心部分就是抽象类的?使用Strategy模式可以在用户需要变化时,修改量很?而且快?
Strategy和Factory有一定的cM,Strategy相对单容易理?q且可以在运行时刻自由切换。Factory重点是用来创建对象?/p>
Strategy适合下列场合:
1.以不同的格式保存文g;
2.以不同的法压羃文g;
3.以不同的法截获图象;
4.以不同的格式输出同样数据的图?比如曲线 或框图bar{?/p>
public class Singleton { private Singleton(){} //在自己内部定义自׃个实例,是不是很奇怪? private static Singleton instance = new Singleton(); //q里提供了一个供外部讉K本class的静态方法,可以直接讉K |
Double-Checked LockingQ用于多U程应用E序
public class Singleton {
private static Singleton instance = null; } |
有时Qؓ(f)复用而设计的工具q不能够被复用的原因仅仅是因ؓ(f)它的接口与专业应用领域所需要的接口不匹配?br /> 适配器模式有cȝ适配器模式和对象的适配器模式两U不同的形式?br />
一、类的适配器模?br /> cȝ适配器模式把适配的类的API转换成目标类的API?br />
有一个很典型的例子就是编译系l。通常我们编译系l分解ؓ(f)QCompile和Link两个步骤。一个Compile又可以分解ؓ(f)词法分析、语法分析、语义分析、中间代码生成等{步骤。对于用hԌ我们不可能将q些模块分别提供l他们,让他们依ơ调用。相反的Q我们应该提供一个统一的接口,使得用户可以方便的用各个功能,例如IDE ?/p>
Facade一个典型应用就是数据库JDBC的应?如下例对数据库的操作:
public class DBCompare { Connection conn = null; |
上例是Jsp中最通常的对数据库操作办?
在应用中,l常需要对数据库操?每次都写上述一D代码肯定比较麻?需要将其中不变的部分提炼出?做成一个接?q就引入了facade外观对象.如果以后我们更换Class.forName中的<driver>也非常方?比如从Mysql数据库换到Oracle数据?只要更换facade接口中的driver可?
我们做成了一?a target="_blank">Facade接口,使用该接?上例中的E序可以更改如?
public class DBCompare { |
可见非常?所有程序对数据库访问都是用改接口,降低pȝ的复杂?增加了灵zL?
如果我们要用连接池,也只要针对facade接口修改可?
׃囑֏以看? facade实际上是个理系l间关系,降低pȝ间耦合度的一个常用的办法,也许你已l不知不觉在使用,管不知道它?yu)是facade.
M事物对象都有抽象和行Z分,例如人,人是一U抽象,人分男h和女人等Qh有行为,行ؓ(f)也有各种具体表现Q所以,“h”与“h的行为”两个概念也反映了抽象和行ؓ(f)之分?/p>
在面向对象设计的基本概念中,对象q个概念实际是由属性和行ؓ(f)两个部分l成的,属性我们可以认为是一U静止的Q是一U抽象,一般情况下Q行为是包含在一个对象中Q但是,在有的情况下Q我们需要将q些行ؓ(f)也进行归c,形成一个ȝ行ؓ(f)接口Q这是桥模式的用处?br />
MQBridge模式是使抽象和行ؓ(f)分离Q做到各自的独立发展Q就是说抽象和行为各抽象Z个接口。当需要扩展行为或者抽象部分时Q?br />只需扩展相应部分Q而不用修改原来的l构?br /> Bridge模式是这样实现的Q?br />//抽象部分 private ToolDraw toolDraw; //行ؓ(f)部分 做一个SingletoncL联系抽象和行为。通过此类来选工?br />public class ToolDrawSingleton{ 假如我们现在要用_笔来画一个方?一个圆形:(x) 例子二:(x) 但是Q我们注意到Q上面四个子cM有概念重叠,可从另外一个角度进行考虑Q这四个cd际是两个角色的组合:(x)抽象 和行为,其中抽象为:(x)中杯和大杯;行ؓ(f)为:(x)加奶 不加Ӟ如加汁 加苹果汁Q? 实现四个子类在抽象和行ؓ(f)之间发生了固定的l定关系Q如果以后动态增加加葡萄汁的行ؓ(f)Q就必须再增加两个类Q中杯加葡萄汁和大杯加葡萄汁。显然?扩展性极差?/p>
那我们从分离抽象和行为的角度Q用Bridge模式来实现?/p>
如何实现?
先看看抽象部分的接口代码:
其中CoffeeImp 是加不加奶的行ؓ(f)接口,看其代码如下:
现在我们有了两个抽象c?下面我们分别对其q行l承,实现concrete class:
//中杯 //大杯 上面分别是中杯和大杯的具体实?下面再对行ؓ(f)CoffeeImpq行l承:
//加奶 //不加?br />public class FragrantCoffeeImp extends CoffeeImp Bridge模式的基本框架我们已l搭好了,别忘记定义中q有一?动态结?我们现在可以喝到臛_四种咖啡: 看看是如何动态结合的,在用之?我们做个准备工作,设计一个单态类(Singleton)用来hold当前的CoffeeImp:
看看中杯加奶 和大杯加?是怎么出来? //拿出牛奶 注意: Bridge模式的执行类如CoffeeImp和Coffee是一对一的关p? 正确创徏CoffeeImp是该模式的关键?br />
例子一Q?/strong>
假如有个cDrawGraph有个d的接口,当然q个圆Ş可以用铅W画Q也可以用钢W画。其中画圆是抽象部分Q?br />用铅W画和用钢笔L行ؓ(f)部分。往往q个时候我们分别会(x)定义铅笔cPencilDrawQ钢W类PenDraw来实现DrawQ?br />q样׃得抽象部分和行ؓ(f)部分固定的捆l在一P扩展性不强。假如要动态增加一个用_笔ȝ行ؓ(f)和一个画方Ş的抽象部分,
必然要新定义一个ChalkDrawc,DrawGraphc里增加drawRectangle接口。显然这是很ȝ的?/p>
public abstract class DrawGraph {
public void setToolDraw(){
this.toolDraw = ToolDrawSingleton.getToolDraw();//用Singleton模式来选工兗?/strong>
}
public ToolDraw getToolDraw(){
return toolDraw;
}
public abstract void draw();
}
//d
public class DrawCircle implements DrawGraph{
public DrawCircle(){
setToolDraw();
}
public void draw(){
System.out.pritnln(toolDraw.getName() + " draw circle");
}
}
//ȝ?br />public class DrawRectangle implements DrawGraph{
public DrawRectangle(){
setToolDraw();
}
public void draw(){
System.out.pritnln(toolDraw.getName() + " draw rectangle");
}
}
public abstract class ToolDraw{
public abstract String getName();
public abstract void drawWithTool();
}
//铅笔
public class PencilDraw implements ToolDraw{
private final static String name = "Pencil";
public static String getName(){
return name;
}
public void drawWithTool(){
System.out.println("Draw with Pencil.");
}
}
//钢笔
public class PenDraw implements ToolDraw{
private final static String name = "Pen";
public String getName(){
return name;
}
public void drawWithTool(){
System.out.println("Draw with Pen.");
}
}
//_笔
public class ChalkDraw implements ToolDraw{
private final static String name = "Chalk";
public String getName(){
return name;
}
public void drawWithTool(){
System.out.println("Draw with Chalk.");
}
}
private static ToolDraw toolDraw;
public ToolDrawSingleton(ToolDraw toolDraw){
this.toolDraw = toolDraw
}
public static ToolDraw getToolDraw(){
return toolDraw;
}
}
//取得工具
ToolDrawSingleton tool = new ToolDrawSingleton(new ChalkDraw());
//L?br />DrawGraph drawRectangle = new DrawRectangle();
drawRectangle.draw();
//d?br />drawRectangle = new DrawCircle();
drawRectangle.draw();
例如,一杯咖啡ؓ(f)?子类实现cMؓ(f)四个Q中杯加奶、大杯加奶?中杯不加奶、大杯不加奶?/p>
以上面提到的咖啡 Z. 我们原来打算只设计一个接?抽象c?,使用Bridge模式?我们需要将抽象和行为分开,加奶和不加奶属于行ؓ(f),我们它们抽象成一个专门的行ؓ(f)接口.
public abstract class Coffee
{
CoffeeImp coffeeImp;
public void setCoffeeImp() {
this.CoffeeImp = CoffeeImpSingleton.getTheCoffeImp();
}
public CoffeeImp getCoffeeImp() {return this.CoffeeImp;}
public abstract void pourCoffee();
}
public abstract class CoffeeImp
{
public abstract void pourCoffeeImp();
}
public class MediumCoffee extends Coffee
{
public MediumCoffee() {setCoffeeImp();}
public void pourCoffee()
{
CoffeeImp coffeeImp = this.getCoffeeImp();
//我们以重复次数来说明是冲中杯q是大杯 ,重复2ơ是中杯
for (int i = 0; i < 2; i++)
{
coffeeImp.pourCoffeeImp();
}
}
}
public class SuperSizeCoffee extends Coffee
{
public SuperSizeCoffee() {setCoffeeImp();}
public void pourCoffee()
{
CoffeeImp coffeeImp = this.getCoffeeImp();
//我们以重复次数来说明是冲中杯q是大杯 ,重复5ơ是大杯
for (int i = 0; i < 5; i++)
{
coffeeImp.pourCoffeeImp();
}
}
}
public class MilkCoffeeImp extends CoffeeImp
{
MilkCoffeeImp() {}
public void pourCoffeeImp()
{
System.out.println("加了味的牛?);
}
}
{
FragrantCoffeeImp() {}
public void pourCoffeeImp()
{
System.out.println("什么也没加,清香");
}
}
1.中杯加奶
2.中杯不加?br />3.大杯加奶
4.大杯不加?/p>
public class CoffeeImpSingleton
{
private static CoffeeImp coffeeImp;
public CoffeeImpSingleton(CoffeeImp coffeeImpIn)
{this.coffeeImp = coffeeImpIn;}
public static CoffeeImp getTheCoffeeImp()
{
return coffeeImp;
}
}
CoffeeImpSingleton coffeeImpSingleton = new CoffeeImpSingleton(new MilkCoffeeImp());
//中杯加奶
MediumCoffee mediumCoffee = new MediumCoffee();
mediumCoffee.pourCoffee();
//大杯加奶
SuperSizeCoffee superSizeCoffee = new SuperSizeCoffee();
superSizeCoffee.pourCoffee();
]]>