基于Java的建造设计模式
基于Java的建造设计模式,基于Java的建造设计模式
前几天陪朋友去装机店攒了一台电脑,看着装机工在那里熟练的装配着机器,不禁想起来了培训时讲到的建造模式。作为装机工,他们不用管你用的CPU是Intel还是AMD,也不管你的显卡是2000千大元还是白送的,都能挛宄淖芭湓谝黄稹惶≒C就诞生了!当然对于客户来说,你也不知道太多关于PC组装的细节。这和建造模式是多么的相像啊!
今天就来探讨一下建造模式
二、定义与结构
GOF给建造模式的定义为:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。可以将建造模式的精髓概括为:将构造复杂对象的过程和对象的部件解耦。这是对降低耦合、提高可复用性精神的一种贯彻。其实这种精神贯彻在GOF几乎所有的设计模式中。
是不是和上面提到的装机流程相像?
这个很多人认为同抽象工厂模式相似的建造模式用在什么样的设计环境下呢(对于两者的比较稍候讨论)?我认为可以总结为以下环境:当要生成的产品有复杂的内部结构,其中的内部结构由多个对象组成;系统将来可能要改变产品对象的内部结构的构成或者实现方式,比如说产品的一些属性现在是从数据库中得到的,而将来可能从XML中解析得到;而且不能将产品的内部构造完全暴露给客户程序,一是为了可用性,二是为了安全等因素。满足上面的设计环境就可以考虑使用建造模式来搭建框架了。 来看看建造模式的组成吧。
抽象建造者角色:这个角色用来规范产品对象的各个组成成分的建造。一般而言,此角色独立于应用程序的商业逻辑。
具体建造者角色:担任这个角色的是于应用程序紧密相关的类,它们在指导者的调用下创建产品实例。这个角色在实现抽象建造者角色提供的方法的前提下,达到完成产品组装,提供成品的功能。
指导者角色:调用具体建造者角色以创建产品对象。指导者并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者对象。 产品角色:建造中的复杂对象。它要包含那些定义组件的类,包括将这些组件装配成产品的接口。
首先客户程序创建一个指导者对象,一个建造者角色,并将建造者角色传入指导者对象进行配置。然后,指导者按照步骤调用建造者的方法创建产品。最后客户程序从建造者或者指导者那里得到产品。
从建造模式的工作流程来看,建造模式将产品的组装“外部化”到了建造者角色中来。这是和任何正规的工厂模式不一样的——产品的创建是在产品类中完成的。
三、实现
实在找不到太好的例子,我认为《java与模式》中发邮件的例子还算可以。这里我将《Think in Patterns with Java》中的例子放到这里权且充个门面。媒体可以存在不同的表达形式,比如书籍、杂志和网络。这个例子表示不同形式的媒体构造的步骤是相似的,所以可以被提取到指导者角色中去。
import java.util.*;
import junit.framework.*;
//不同的媒体形式:
class Media extends ArrayList {}
class Book extends Media {}
class Magazine extends Media {}
class WebSite extends Media {}
// 进而不含不同的媒体组成元素:
class MediaItem {
private String s;
public MediaItem(String s) { this.s = s; }
public String toString() { return s; }
}
class Chapter extends MediaItem {
public Chapter(String s) { super(s); }
}
class Article extends MediaItem {
public Article(String s) { super(s); }
}
class WebItem extends MediaItem {
public WebItem(String s) { super(s); }
}
// 抽象建造者角色,它规范了所有媒体建造的步骤:
class MediaBuilder {
public void buildBase() {}
public void addMediaItem(MediaItem item) {}
public Media getFinishedMedia() { return null; }
}
//具体建造者角色
class BookBuilder extends MediaBuilder {
private Book b;
public void buildBase() {
System.out.println("Building book framework");
b = new Book();
}
public void addMediaItem(MediaItem chapter) {
System.out.println("Adding chapter " + chapter);
b.add(chapter);
}
public Media getFinishedMedia() { return b; }
}
class MagazineBuilder extends MediaBuilder {
private Magazine m;
public void buildBase() {
System.out.println("Building magazin