1. Factory
定义:提供创建对象的接口.
为何使用?我们需要将创建实例的责任与使用实例的责任分开
public class Factory{ public static Sample creator(){ .... if (which==1) return new MySample(); else if (which==2) return new HisSample(); } }
如何使用?
工厂模式中有: 工厂方法(Factory Method) 抽象工厂(Abstract Factory).
这两个模式没有很明显的区别,区别在于需要创建对象的复杂程度上。如果我们创建对象的方法变得复杂了,我们就可能要将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现
public abstract class Factory{ public abstract Sample creator(); public abstract Sample2 creator(); } public class SimpleFactory extends Factory{ public Sample creator(){ ...... } public Sample2 creator(){ ...... } } public class BombFactory extends Factory{ public Sample creator(){ ...... } public Sample2 creator(){ ...... } }
上例中我们只有一类产品接口 Sample , 工厂方法和抽象工厂可以创建多个产品接口的实例,比如Sample2 Sample3
FactoryMethod 往往只是创建单个的实例。Abstract Factory 创建一系列的实例组,这些实例彼此相关。
2. Prototype
定义:
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.
如何使用?
因为Java 中的提供clone()方法来实现对象的克隆(具体了解clone()按这里),所以
Prototype 模式实现一下子变得很简单.
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; } }
public class SaladSpoon extends AbstractSpoon { public SaladSpoon() { setSpoonName("Salad Spoon"); } }
public class SoupSpoon extends AbstractSpoon { public SoupSpoon() { setSpoonName("Soup Spoon"); } }
AbstractSpoon spoon1 = new SoupSpoon();
AbstractSpoon spoon2 = spoon1.clone();
3. Builder
Builder 模式定义:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.
为何使用?
是为了将构建复杂对象的过程和它的部件解耦.注意: 是解耦过程和部件.
如何使用?
public interface Builder { //创建部件A 比如创建汽车车轮 void buildPartA(); //创建部件B 比如创建汽车方向盘 void buildPartB(); //创建部件C 比如创建汽车发动机 void buildPartC(); //返回最后组装成品结果 (返回最后装配好的汽车) //成品的组装过程不在这里进行,而是转移到下面的Director 类中 进行. //从而实现了解耦过程和部件 Product getResult(); }
public class ConcreteBuilder implements Builder { Part partA, partB, partC; public void buildPartA() { //这里是具体如何构建partA 的代码 }; public void buildPartB() { //这里是具体如何构建partB 的代码 }; public void buildPartC() { //这里是具体如何构建partB 的代码 }; public Product getResult() { //返回最后组装成品结果 }; }
public class Director { private Builder builder; public Director( Builder builder ) { this.builder = builder; } // 将部件partA partB partC 最后组成复杂对象 //这里是将车轮 方向盘和发动机组装成汽车的过程 public void construct() { builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); } }
复杂对象:产品Product:
public interface Product { }
复杂对象的部件:
public interface Part { }
我们看看如何调用Builder 模式:
ConcreteBuilder builder = new ConcreteBuilder();
Director director = new Director( builder );
director.construct();
Product product = builder.getResult();
4. Singleton
定义:
Singleton 模式主要作用是保证在Java 应用程序中,一个Class 只有一个实例存在。
如何使用?
public class Singleton { private static Singleton _instance = new Singleton(); public static Singleton getInstance() { return _instance; } } 调用方法: Singleton.getInstance()
public class Singleton { private static Singleton _instance = null; public static Singleton getInstance() { if (_instance==null) _instancenew Singleton() return _instance; } } 调用方法: Singleton.getInstance()
5. Facade
Facade 的定义: 为子系统中的一组接口提供一个一致的界面.
Facade 一个典型应用就是数据库JDBC 的应用,如下例对数据库的操作:
public class DBCompare { Connection conn = null; PreparedStatement prep = null; ResultSet rset = null; try { Class.forName( "<driver>" ).newInstance(); conn = DriverManager.getConnection( "<database>" ); String sql = "SELECT * FROM <table> WHERE <column name> = ?"; prep = conn.prepareStatement( sql ); prep.setString( 1, "<column value>" ); rset = prep.executeQuery(); if( rset.next() ) { System.out.println( rset.getString( "<column name" ) ); } } catch( SException e ) { e.printStackTrace(); } finally { rset.close(); prep.close(); conn.close(); } }
上例是Jsp 中最通常的对数据库操作办法.
在应用中,经常需要对数据库操作,每次都写上述一段代码肯定比较麻烦,需要将其中不变的
部分提炼出来,做成一个接口,这就引入了facade 外观对象.如果以后我们更换
Class.forName 中的<driver>也非常方便,比如从Mysql 数据库换到Oracle 数据库,只要更
换facade 接口中的driver 就可以.
6.Proxy
Proxy 是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结
构,Proxy 是代理的意思,我们也许有代理服务器等概念,代理概念可以解释为:在出发点到
目的地之间有一道中间层,意为代理.
设计模式中定义: 为其他对象提供一种代理以控制对这个对象的访问.
为什么要使用Proxy?
1.授权机制 不同级别的用户对同一对象拥有不同的访问权利,如Jive 论坛系统中,就使用
Proxy 进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),Jive 中就通过
类似ForumProxy 这样的代理来控制这两种用户对论坛的访问权限.
2.某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.
举例两个具体情况:
(1)如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包
含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片处
理完成,这时需要做个图片Proxy 来代替真正的图片.
(2)如果那个对象在Internet 的某个远端服务器上,直接操作这个对象因为网络速度原因可
能比较慢,那我们可以先用Proxy 来代替那个对象.
总之原则是,对于开销很大的对象,只有在使用它时才创建,这个原则可以为我们节省很多宝
贵的Java 内存. 所以,有些人认为Java 耗费资源内存,我以为这和程序编制思路也有一定的
关系.
public class ForumProxy implements Forum { private ForumPermissions permissions; private Forum forum; this.authorization = authorization; public ForumProxy(Forum forum, Authorization authorization, ForumPermissions permissions) { this.forum = forum; this.authorization = authorization; this.permissions = permissions; } ..... public void setName(String name) throws UnauthorizedException, ForumAlreadyExistsException { //只有是系统或论坛管理者才可以修改名称 if (permissions.isSystemOrForumAdmin()) { forum.setName(name); } else { throw new UnauthorizedException(); } }
而DbForum 才是接口Forum 的真正实现,以修改论坛名称为例:
public class DbForum implements Forum, Cacheable { ... public void setName(String name) throws ForumAlreadyExistsException { .... this.name = name; //这里真正将新名称保存到数据库中 saveToDb(); .... } ... }
7.Adapter
定义:
将两个不兼容的类纠合在一起使用,属于结构型模式,需要有Adaptee(被适配者)和
Adaptor(适配器)两个身份.
为何使用?
我们经常碰到要将两个没有关系的类组合在一起使用,第一解决方案是:修改各自类的接口,
但是如果我们没有源代码,或者,我们不愿意为了一个应用而修改各自的接口。 怎么办?
使用Adapter,在这两种接口之间创建一个混合接口(混血儿).
如何使用?
实现Adapter 方式,其实"think in Java"的"类再生"一节中已经提到,有两种方式:组合
(composition)和继承(inheritance).
假设我们要打桩,有两种类:方形桩 圆形桩.
public class SquarePeg{ public void insert(String str){ System.out.println("SquarePeg insert():"+str); } } public class RoundPeg{ public void insertIntohole(String msg){ System.out.println("RoundPeg insertIntoHole():"+msg); } }
public class PegAdapter extends SquarePeg{ private RoundPeg roundPeg; public PegAdapter(RoundPeg peg)(this.roundPeg=peg;) public void insert(String str){ roundPeg.insertIntoHole(str);} }
8.Composite
Composite 定义:
将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和
组合对象的使用具有一致性.
Composite 比较容易理解,想到Composite 就应该想到树形结构图。组合体内这些对象都有
共同接口,当组合体一个对象的方法被调用执行时,Composite 将遍历(Iterator)整个树形
结构,寻找同样包含这个方法的对象并实现调用执行。可以用牵一动百来形容。
所以Composite 模式使用到Iterator 模式,和Chain of Responsibility 模式类似。
Composite 好处:
1.使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关系自
己处理的是单个对象还是整个组合结构,这就简化了客户端代码。
2.更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。
public abstract class Equipment { private String name; //网络价格 public abstract double netPrice(); //折扣价格 public abstract double discountPrice(); //增加部件方法 public boolean add(Equipment equipment) { return false; } //删除部件方法 public boolean remove(Equipment equipment) { return false; } //注意这里,这里就提供一种用于访问组合体类的部件方法。 public Iterator iter() { return null; } public Equipment(final String name) { this.name=name; } }
public class Disk extends Equipment { public Disk(String name) { super(name); } //定义Disk 网络价格为1 public double netPrice() { return 1.; } //定义了disk 折扣价格是0.5 对折。 public double discountPrice() { return .5; } }
abstract class CompositeEquipment extends Equipment { private int i=0; //定义一个Vector 用来存放'儿子' private Lsit equipment=new ArrayList(); public CompositeEquipment(String name) { super(name); } public boolean add(Equipment equipment) { this.equipment.add(equipment); return true; } public double netPrice() { double netPrice=0.; Iterator iter=equipment.iterator(); for(iter.hasNext()) netPrice+=((Equipment)iter.next()).netPrice(); return netPrice; } public double discountPrice() { double discountPrice=0.; Iterator iter=equipment.iterator(); for(iter.hasNext()) 设计模式(Patterns in Java) -- http://www.jdon.com 35 discountPrice+=((Equipment)iter.next()).discountPrice(); return discountPrice; } //注意这里,这里就提供用于访问自己组合体内的部件方法。 //上面dIsk 之所以没有,是因为Disk 是个单独(Primitive)的元素. public Iterator iter() { return equipment.iterator() ; { //重载Iterator 方法 public boolean hasNext() { return i<equipment.size(); } //重载Iterator 方法 public Object next() { if(hasNext()) return equipment.elementAt(i++); else throw new NoSuchElementException(); } }
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 { 设计模式(Patterns in Java) -- http://www.jdon.com 36 public Cabinet(String name) { super(name); } public double netPrice() { return 1.+super.netPrice(); } public double discountPrice() { return .5+super.discountPrice(); } }
至此我们完成了整个Composite 模式的架构。
我们可以看看客户端调用Composote 代码:
Cabinet cabinet=new Cabinet("Tower");
Chassis chassis=new Chassis("PC Chassis");
//将PC Chassis 装到Tower 中 (将盘盒装到箱子里)
cabinet.add(chassis);
//将一个10GB 的硬盘装到 PC Chassis (将硬盘装到盘盒里)
chassis.add(new Disk("10 GB"));
//调用 netPrice()方法;
System.out.println("netPrice="+cabinet.netPrice());
System.out.println("discountPrice="+cabinet.discountPrice());
上面调用的方法netPrice()或discountPrice(),实际上Composite 使用Iterator 遍历了
整个树形结构,寻找同样包含这个方法的对象并实现调用执行.
Composite 是个很巧妙体现智慧的模式,在实际应用中,如果碰到树形结构,我们就可以尝
试是否可以使用这个模式。
9.Decorator
Decorator 定义:
动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator 模式相比用生成
子类方式达到功能的扩充显得更为灵活.
为什么使用Decorator?
我们通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势
必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓
展功能,这些功能是编译时就确定了,是静态的.
使用Decorator 的理由是:这些功能需要由用户动态决定加入的方式和时机.Decorator 提供
了"即插即用"的方法,在运行期间决定何时增加何种功能.
public interface Work { public void insert(); } public class SquarePeg implements Work{ public void insert(){ System.out.println("方形桩插入"); } } public class Decorator implements Work{ private Work work; //额外增加的功能被打包在这个List 中 private ArrayList others = new ArrayList(); //在构造器中使用组合new 方式,引入Work 对象; public Decorator(Work work) { this.work=work; others.add("挖坑"); others.add("钉木板"); } public void insert(){ newMethod(); } //在新方法中,我们在insert 之前增加其他方法,这里次序先后是用 户灵活指定的 public void newMethod() { otherMethod(); work.insert(); } public void otherMethod() { ListIterator listIterator = others.listIterator(); while (listIterator.hasNext()) { System.out.println(((String)(listIterator.next())) + " 正在进行"); } } }
好了,Decorator 模式出来了,我们看如何调用:
Work squarePeg = new SquarePeg();
Work decorator = new Decorator(squarePeg);
decorator.insert();
Decorator 模式至此完成.
如果你细心,会发现,上面调用类似我们读取文件时的调用:
FileReader fr = new FileReader(filename);
BufferedReader br = new BufferedReader(fr);
实际上Java 的I/O API 就是使用Decorator 实现的,I/O 变种很多,如果都采取继承方法,
将会产生很多子类,显然相当繁琐
10.Bridge
Bridge 定义 :
将抽象和行为划分开来,各自独立,但能动态的结合.
为什么使用?
通常,当一个抽象类或接口有多个具体实现(concrete subclass),这些concrete 之间关系可
能有以下两种:
1. 这多个具体实现之间恰好是并列的,如前面举例,打桩,有两个concrete class:方形桩和
圆形桩;这两个形状上的桩是并列的,没有概念上的重复,那么我们只要使用继承就可以了.
2.实际应用上,常常有可能在这多个concrete class 之间有概念上重叠.那么需要我们把抽
象共同部分和行为共同部分各自独立开来,原来是准备放在一个接口里,现在需要设计两个
接口,分别放置抽象和行为.
例如,一杯咖啡为例,有中杯和大杯之分,同时还有加奶 不加奶之分. 如果用单纯的继承,这
四个具体实现(中杯 大杯 加奶 不加奶)之间有概念重叠,因为有中杯加奶,也有中杯不加奶,
如果再在中杯这一层再实现两个继承,很显然混乱,扩展性极差.那我们使用Bridge 模式来
实现它.
如何实现?
以上面提到的咖啡 为例. 我们原来打算只设计一个接口(抽象类),使用Bridge 模式后,我
们需要将抽象和行为分开,加奶和不加奶属于行为,我们将它们抽象成一个专门的行为接口.
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(); //我们以重复次数来说明是冲中杯还是大杯 ,重复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(); //我们以重复次数来说明是冲中杯还是大杯 ,重复5 次是大杯 for (int i = 0; i < 5; i++) { coffeeImp.pourCoffeeImp(); } } }
//加奶 public class MilkCoffeeImp extends CoffeeImp { MilkCoffeeImp() {} public void pourCoffeeImp() { System.out.println("加了美味的牛奶"); } } //不加奶 public class FragrantCoffeeImp extends CoffeeImp { FragrantCoffeeImp() {} public void pourCoffeeImp() { System.out.println("什么也没加,清香"); } }
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();
注意: Bridge 模式的执行类如CoffeeImp 和Coffee 是一对一的关系, 正确创建CoffeeImp
是该模式的关键,
11.Flyweight
Flyweight 定义:
避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类).
为什么使用?
面向对象语言的原则就是一切都是对象,但是如果真正使用起来,有时对象数可能显得很庞
大,比如,字处理软件,如果以每个文字都作为一个对象,几千个字,对象数就是几千,无疑耗
费内存,那么我们还是要"求同存异",找出这些对象群的共同点,设计一个元类,封装可以被
共享的类,另外,还有一些特性是取决于应用(context),是不可共享的,这也Flyweight 中两
个重要概念内部状态intrinsic 和外部状态extrinsic 之分.
说白点,就是先捏一个的原始模型,然后随着不同场合和环境,再产生各具特征的具体模型,
很显然,在这里需要产生不同的新对象,所以Flyweight 模式中常出现Factory 模
式.Flyweight 的内部状态是用来共享的,Flyweight factory 负责维护一个Flyweight
pool(模式池)来存放内部状态的对象.
Flyweight 模式是一个提高程序效率和性能的模式,会大大加快程序的运行速度.应用场合
很多:比如你要从一个数据库中读取一系列字符串,这些字符串中有许多是重复的,那么我们
可以将这些字符串储存在Flyweight 池(pool)中.
public interface Flyweight { public void operation( ExtrinsicState state ); } //用于本模式的抽象数据类型(自行设计) public interface ExtrinsicState { }
public class ConcreteFlyweight implements Flyweight { private IntrinsicState state; public void operation( ExtrinsicState state ) { //具体操作 } }
public class UnsharedConcreteFlyweight implements Flyweight { public void operation( ExtrinsicState state ) { } }
Flyweight factory 负责维护一个Flyweight 池(存放内部状态),当客户端请求一个共享
Flyweight 时,这个factory 首先搜索池中是否已经有可适用的,如果有,factory 只是简单返
回送出这个对象,否则,创建一个新的对象,加入到池中,再返回送出这个对象.池
public class FlyweightFactory { //Flyweight pool private Hashtable flyweights = new Hashtable(); public Flyweight getFlyweight( Object key ) { Flyweight flyweight = (Flyweight) flyweights.get(key); if( flyweight == null ) { //产生新的ConcreteFlyweight flyweight = new ConcreteFlyweight(); flyweights.put( key, flyweight ); } return flyweight; } }
至此,Flyweight 模式的基本框架已经就绪,我们看看如何调用:
FlyweightFactory factory = new FlyweightFactory();
Flyweight fly1 = factory.getFlyweight( "Fred" );
Flyweight fly2 = factory.getFlyweight( "Wilma" );
12.Template
Template 定义:
定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中.
public abstract class Benchmark { /** * 下面操作是我们希望在子类中完成 */ public abstract void benchmark(); /** * 重复执行benchmark 次数 */ public final long repeat (int count) { if (count <= 0) return 0; else { long startTime = System.currentTimeMillis(); for (int i = 0; i < count; i++) benchmark(); long stopTime = System.currentTimeMillis(); return stopTime - startTime; } } }
public class MethodBenchmark extends Benchmark { /** * 真正定义benchmark 内容 */ public void benchmark() { for (int i = 0; i < Integer.MAX_VALUE; i++){ System.out.printtln("i="+i); } } }
Benchmark operation = new MethodBenchmark();
long duration = operation.repeat(Integer.parseInt(args[0].trim()));
System.out.println("The operation took " + duration + " milliseconds");
13.Memento
Memento 定义:
memento 是一个保存另外一个对象内部状态拷贝的对象.这样以后就可以将该对象恢复到原
先保存的状态.
public class Originator { private int number; private File file = null; public Originator(){} // 创建一个Memento public Memento getMemento(){ return new Memento(this); } // 恢复到原始值 public void setMemento(Memento m){ number = m.number; file = m.file; } }
private class Memento implements java.io.Serializable{ private int number; private File file = null; public Memento( Originator o){ number = o.number; file = o.file; } }
可见 Memento 中保存了Originator 中的number 和file 的值. 通过调用Originator 中
number 和file 值改变的话,通过调用setMemento()方法可以恢复.
Memento 模式的缺点是耗费大,如果内部状态很多,再保存一份,无意要浪费大量内存.
14.Observer
public class product extends Observable{ private String name; private float price; public String getName(){ return name;} public void setName(){ this.name=name; //设置变化点 setChanged(); notifyObservers(name); } public float getPrice(){ return price;} public void setPrice(){ this.price=price; //设置变化点 setChanged(); notifyObservers(new Float(price)); } //以下可以是数据库更新 插入命令. public void saveToDb(){ ..................... }
//观察者NameObserver 主要用来对产品名称(name)进行观察的 public class NameObserver implements Observer{ private String name=null; public void update(Observable obj,Object arg){ if (arg instanceof String){ name=(String)arg; //产品名称改变值在name 中 System.out.println("NameObserver :name changet to "+name); } } } //观察者PriceObserver 主要用来对产品价格(price)进行观察的 public class PriceObserver implements Observer{ private float price=0; public void update(Observable obj,Object arg){ if (arg instanceof Float){ price=((Float)arg).floatValue(); System.out.println("PriceObserver :price changet to "+price); } } }
Product product=new Product();
NameObserver nameobs=new NameObserver();
PriceObserver priceobs=new PriceObserver();
//加入观察者
product.addObserver(nameobs);
product.addObserver(priceobs);
product.setName("橘子红了");
product.setPrice(9.22f);
15.Chain of Responsibility
Chain of Responsibility 定义
Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些
类之间是一个松散的耦合,唯一共同点是在他们之间传递request. 也就是说,来了一个请
求,A 类先处理,如果没有处理,就传递到B 类处理,如果没有处理,就传递到C 类处理,
就这样象一个链条(chain)一样传递下去。
CoR 的优点:
因为无法预知来自外界的请求是属于哪种类型,每个类如果碰到它不能处理的请求只要放弃
就可以。无疑这降低了类之间的耦合性。
缺点是效率低,因为一个请求的完成可能要遍历到最后才可能完成,当然也可以用树的概念
优化。 在Java AWT1.0 中,对于鼠标按键事情的处理就是使用CoR,到Java.1.1 以后,就
使用Observer 代替CoR
扩展性差,因为在CoR 中,一定要有一个统一的接口Handler.局限性就在这里。
16.Command
Command 定义
不少Command 模式的代码都是针对图形界面的,它实际就是菜单命令,我们在一个下拉菜单
选择一个命令时,然后会执行一些动作.
将这些命令封装成在一个类中,然后用户(调用者)再对这个类进行操作,这就是Command 模
式,换句话说,本来用户(调用者)是直接调用这些命令的,如菜单上打开文档(调用者),就直
接指向打开文档的代码,使用Command 模式,就是在这两者之间增加一个中间者,将这种直接
关系拗断,同时两者之间都隔离,基本没有关系了.
显然这样做的好处是符合封装的特性,降低耦合度,Command 是将对行为进行封装的典型模
式,Factory 是将创建进行封装的模式,
从Command 模式,我也发现设计模式一个"通病":好象喜欢将简单的问题复杂化, 喜欢在不
同类中增加第三者,当然这样做有利于代码的健壮性 可维护性 还有复用性.
如何使用?
具体的Command 模式代码各式各样,因为如何封装命令,不同系统,有不同的做法.下面事例
是将命令封装在一个Collection 的List 中,任何对象一旦加入List 中,实际上装入了一个
封闭的黑盒中,对象的特性消失了,只有取出时,才有可能模糊的分辨出:
典型的Command 模式需要有一个接口.接口中有一个统一的方法,这就是"将命令/请求封装
为对象":
public interface Command { public abstract void execute ( ); } public class Engineer implements Command { public void execute( ) { //do Engineer's command } } public class Programmer implements Command { public void execute( ) { //do programmer's command } } public class Politician implements Command { public void execute( ) { //do Politician's command } } public class producer{ public static List produceRequests() { List queue = new ArrayList(); queue.add( new Engineer() ); queue.add( new Politician() ); queue.add( new Programmer() ); return queue; } }
public class TestCommand { public static void main(String[] args) { List queue = Producer.produceRequests(); for (Iterator it = queue.iterator(); it.hasNext(); ) //取出List 中东东,其他特征都不能确定,只能保证一 个特征是100%正确, // 他们至少是接口Command 的"儿子".所以强制转换 类型为接口Command ((Command)it.next()).execute(); } }
17.State/Strategy
State 的定义: 不同的状态,不同的行为;或者说,每个状态有着相应的行为.
何时使用?
State 模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elseif else
进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取
State 模式了.
不只是根据状态,也有根据属性.如果某个对象的属性不同,对象的行为就不一样,这点在数
据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property 属性含义的字
段,用以标识记录中一些特殊性质的记录,这种属性的改变(切换)又是随时可能发生的,就有
可能要使用State.
--------------------------------------------------
Strategy 是属于设计模式中 对象行为型模式,主要是定义一系列的算法,把这些算法一个
个封装成单独的类.
18.Mediator
Mediator 定义:
用一个中介对象来封装一系列关于对象交互行为.
为何使用Mediator?
各个对象之间的交互操作非常多;每个对象的行为操作都依赖彼此对方,修改一个对象的行
为,同时会涉及到修改很多其他对象的行为,如果使用Mediator 模式,可以使各个对象间的
耦合松散,只需关心和 Mediator 的关系,使多对多的关系变成了一对多的关系,可以降低系
统的复杂性,提高可修改扩展性.
public interface Mediator { }
public class ConcreteMediator implements Mediator {
//假设当前有两个成员.
private ConcreteColleague1 colleague1 = new ConcreteColleague1();
private ConcreteColleague2 colleague2 = new ConcreteColleague2();
...
}
public class Colleague { private Mediator mediator; public Mediator getMediator() { return mediator; } public void setMediator( Mediator mediator ) { this.mediator = mediator; } } public class ConcreteColleague1 { } public class ConcreteColleague2 { }
每个成员都必须知道Mediator,并且和 Mediator 联系,而不是和其他成员联系.
至此,Mediator 模式框架完成,可以发现Mediator 模式规定不是很多,大体框架也比较简单,
但实际使用起来就非常灵活.
Mediator 模式在事件驱动类应用中比较多,例如界面设计GUI.;聊天,消息传递等,在聊天应
用中,需要有一个MessageMediator,专门负责request/reponse 之间任务的调节.
MVC 是J2EE 的一个基本模式,View Controller 是一种Mediator,它是Jsp 和服务器上应用
程序间的Mediator.
19.Interpreter
Interpreter 定义:
定义语言的文法 ,并且建立一个解释器来解释该语言中的句子.
20.Visitor
Visitor 定义
作用于某个对象群中各个对象的操作. 它可以使你在不改变这些对象本身的情况下,定义作
用于这些对象的新操作.