您的位置:软件 > 开发者网络 > 开发工具 > Java > 正文
深入浅出基于Java的建造设计模式
[文章信息]
作者:Ai92
时间:2005-01-20
出处:blog
责任编辑:方舟
[文章导读]
GOF给建造模式的定义为:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
advertisement
热点推荐
· 迷你迅雷给IE下载加足马力
· 《大话李白》主题曲 Flash
· Windows操作系统小技巧荟萃(上)
· 新浪UC2005使用技巧四则
· Google 2秒钟搜索100G硬盘
[正文]
  一、引子

  前几天陪朋友去装机店攒了一台电脑,看着装机工在那里熟练的装配着机器,不禁想起来了培训时讲到的建造模式。作为装机工,他们不用管你用的CPU是Intel还是AMD,也不管你的显卡是2000千大元还是白送的,都能三下五除二的装配在一起——一台PC就诞生了!当然对于客户来说,你也不知道太多关于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 magazine framework");
  m = new Magazine();
 }

 public void addMediaItem(MediaItem article) {
  System.out.println("Adding article " + article);
  m.add(article);
 }
 public Media getFinishedMedia() { return m; }
}

class WebSiteBuilder extends MediaBuilder {
 private WebSite w;
 public void buildBase() {
  System.out.println("Building web site framework");
  w = new WebSite();
 }

 public void addMediaItem(MediaItem webItem) {
  System.out.println("Adding web item " + webItem);
  w.add(webItem);
 }

 public Media getFinishedMedia() { return w; }
}

//指导者角色,也叫上下文
class MediaDirector {
 private MediaBuilder mb;
 public MediaDirector(MediaBuilder mb) {
  this.mb = mb; //具有策略模式相似特征的
 }

 public Media produceMedia(List input) {
  mb.buildBase();
  for(Iterator it = input.iterator(); it.hasNext();)
   mb.addMediaItem((MediaItem)it.next());
   return mb.getFinishedMedia();
 }
};

//测试程序——客户程序角色

public class BuildMedia extends TestCase {
 private List input = Arrays.asList(new MediaItem[] {
  new MediaItem("item1"), new MediaItem("item2"),
  new MediaItem("item3"), new MediaItem("item4"),
 });

 public void testBook() {
  MediaDirector buildBook = new MediaDirector(new BookBuilder());
  Media book = buildBook.produceMedia(input);
  String result = "book: " + book;
  System.out.println(result);
  assertEquals(result, "book: [item1, item2, item3, item4]");
 }

 public void testMagazine() {
  MediaDirector buildMagazine = new MediaDirector(new MagazineBuilder());
  Media magazine = buildMagazine.produceMedia(input);
  String result = "magazine: " + magazine;
  System.out.println(result);
  assertEquals(result, "magazine: [item1, item2, item3, item4]");
 }

 public void testWebSite(){
  MediaDirector buildWebSite = new MediaDirector(new WebSiteBuilder());
  Media webSite = buildWebSite.produceMedia(input);
  String result = "web site: " + webSite;
  System.out.println(result);
  assertEquals(result, "web site: [item1, item2, item3, item4]");
 }

 public static void main(String[] args) {
  junit.textui.TestRunner.run(BuildMedia.class);
 }

}

  在实现的时候,抽象建造角色提供的接口必须足够普遍,以适应不同的具体建造角色。对于一个建造角色来说可能某个步骤是不需要的,可以将此接口实现为空。多个产品之间可能没有太多的共同点,可以提供一个标示接口作为抽象产品角色;也可以不提供抽象产品角色,这时要将提供产品的接口从抽象建造角色里面去掉,不然就会编译出问题。

  四、应用优点

  建造模式可以使得产品内部的表象独立变化。在原来的工厂方法模式中,产品内部的表象是由产品自身来决定的;而在建造模式中则是“外部化”为由建造者来负责。这样定义一个新的具体建造者角色就可以改变产品的内部表象,符合“开闭原则”。

  建造模式使得客户不需要知道太多产品内部的细节。它将复杂对象的组建和表示方式封装在一个具体的建造角色中,而且由指导者来协调建造者角色来得到具体的产品实例。

  每一个具体建造者角色是毫无关系的。

  建造模式可以对复杂产品的创建进行更加精细的控制。产品的组成是由指导者角色调用具体建造者角色来逐步完成的,所以比起其它创建型模式能更好的反映产品的构造过程。

  五、扩展

  建造模式中很可能要用到组成成品的各种组件类,对于这些类的创建可以考虑使用工厂方法或者原型模式来实现,在必要的时候也可以加上单例模式来控制类实例的产生。但是要坚持一个大前提就是要使引入的模式给你的系统带来好处,而不是臃肿的结构。 建造模式在得到复杂产品的时候可能要引用多个不同的组件,在这一点上来看,建造模式和抽象工厂模式是相似的。可以从以下两点来区分两者:创建模式着重于逐步将组件装配成一个成品并向外提供成品,而抽象工厂模式着重于得到产品族中相关的多个产品对象;抽象工厂模式的应用是受限于产品族的(具体参见《深入浅出工厂模式》),建造模式则不会。

  由于建造模式和抽象工厂模式在实现功能上相似,所以两者使用的环境都比较复杂并且需要更多的灵活性。 建造模式中可能要使用到不同“大小”的组件类,因此这时也经常和合成模式在一起使用。

发表评论推荐给朋友我想参加相关培训打印我对此感兴趣订阅电子杂志
相关内容焦点新闻
  • 软件体系架构模式在J2EE中的应用
  • JBuilder和JDeveloper的简单比较
  • 实战Java多线程编程精要之实现线程
  • 实战体会Java多线程编程精要之基础
  • 网络游戏服务器端开发心得之网络
  • 寄出钱易趣说没收到 网上购物“优惠”遭质疑
  • 内地C2C网站集体对接海外 扩展两岸三地市场
  • 企业信息化时代的新兴职业:客户关系管理师
  • 诺基亚光辉岂止区区15年 CEO奥利拉不信邪
  • CN域名注册价格大跳水 将与.COM域名持平
  • 中国将制定首个国家信息化战略 年底前发布
  • 04年中国企业十大新闻揭晓 联想收购列第一
  • 跨国公司在华兴独资浪潮 欧盟与日本打头阵
  • Advertisement

    天极无线


    奇妙科幻|美好风光|清风车影|漫画卡通|星座生肖|明星写真|动物世界
    老鼠爱大米
    挥着翅膀的女孩
    女人味
    栀子花开
    白月光
    刚刚好
    江南
    快乐崇拜
    亲爱的你怎么不在我身边
    小薇
    2002年的第一场雪
    有多少爱可以重来
    我的地盘
    七里香
    情人
     
    老鼠爱大米 老板电话
    冲动的惩罚 七里香
    我不是黄蓉 女生撒娇
    盛夏的果实 坚持到底
    孤单北半球 眉飞色舞
    挪威的森林 可爱女人
    最浪漫的事 老板电话

    CSEEK搜索