深入浅出基于Java的制作设计模式
副标题#e#
一、引子
前几天伴随侣去装机店攒了一台电脑,看着装机工在哪里纯熟的装配着呆板,不禁想起来了培训时讲到的制作模式。作为装机工,他们不消管你用的CPU是Intel照旧AMD,也不管你的显卡是2000千大元照旧白送的,都能三下五除二的装配在一起——一台PC就降生了!虽然对付客户来说,你也不知道太多关于PC组装的细节。这和制作模式是何等的相像啊!
本日就来探讨一下制作模式
二、界说与布局
GOF给制作模式的界说为:将一个巨大工具的构建与它的暗示疏散,使得同样的构建进程可以建设差异的暗示。可以将制作模式的精华归纳综合为:将结构巨大工具的进程和工具的部件解耦。这是对低落耦合、提高可复用性精力的一种贯彻。其实这种精力贯彻在GOF险些所有的设计模式中。
是不是和上面提到的装机流程相像?
这个许多人认为同抽象工场模式相似的制作模式用在什么样的设计情况下呢(对付两者的较量稍候接头)?我认为可以总结为以下情况:当要生成的产物有巨大的内部布局,个中的内部布局由多个工具构成;系统未来大概要改变产物工具的内部布局的组成可能实现方法,好比说产物的一些属性此刻是从数据库中获得的,而未来大概从XML中理会获得;并且不能将产物的内部结构完全袒露给客户措施,一是为了可用性,二是为了安详等因素。满意上面的设计情况就可以思量利用制作模式来搭建框架了。 来看看制作模式的构成吧。
抽象制作者脚色:这个脚色用来类型产物工具的各个构成身分的制作。一般而言,此脚色独立于应用措施的贸易逻辑。
详细制作者脚色:接受这个脚色的是于应用措施细密相关的类,它们在指导者的挪用下建设产物实例。这个脚色在实现抽象制作者脚色提供的要领的前提下,到达完成产物组装,提供制品的成果。
指导者脚色:挪用详细制作者脚色以建设产物工具。指导者并没有产物类的详细常识,真正拥有产物类的详细常识的是详细制作者工具。 产物脚色:制作中的巨大工具。它要包括那些界说组件的类,包罗将这些组件装配成产物的接口。
来看下这些脚色构成的类图:
首先客户措施建设一个指导者工具,一个制作者脚色,并将制作者脚色传入指导者工具举办设置。然后,指导者凭据步调挪用制作者的要领建设产物。最后客户措施从制作者可能指导者哪里获得产物。
从制作模式的事情流程来看,制作模式将产物的组装“外部化”到了制作者脚色中来。这是和任何正规的工场模式纷歧样的——产物的建设是在产物类中完成的。
#p#副标题#e#
三、实现
实在找不到太好的例子,我认为《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);
}
}
#p#分页标题#e#
在实现的时候,抽象制作脚色提供的接口必需足够普遍,以适应差异的详细制作脚色。对付一个制作脚色来说大概某个步调是不需要的,可以将此接话柄现为空。多个产物之间大概没有太多的配合点,可以提供一个标示接口作为抽象产物脚色;也可以不提供抽象产物脚色,这时要将提供产物的接口从抽象制作脚色内里去掉,否则就会编译出问题。
四、应用利益
制作模式可以使得产物内部的表象独立变革。在本来的工场要领模式中,产物内部的表象是由产物自身来抉择的;而在制作模式中则是“外部化”为由制作者来认真。这样界说一个新的详细制作者脚色就可以改变产物的内部表象,切合“开闭原则”。
制作模式使得客户不需要知道太多产物内部的细节。它将巨大工具的组建和暗示方法封装在一个详细的制作脚色中,并且由指导者来协调制作者脚色来获得详细的产物实例。
每一个详细制作者脚色是毫无干系的。
制作模式可以对巨大产物的建设举办越发风雅的节制。产物的构成是由指导者脚色挪用详细制作者脚色来慢慢完成的,所以比起其它建设型模式能更好的反应产物的结构进程。
五、扩展
制作模式中很大概要用到构成制品的各类组件类,对付这些类的建设可以思量利用工场要领可能原型模式来实现,在须要的时候也可以加上单例模式来节制类实例的发生。可是要僵持一个大前提就是要使引入的模式给你的系统带来长处,而不是臃肿的布局。 制作模式在获得巨大产物的时候大概要引用多个差异的组件,在这一点上来看,制作模式和抽象工场模式是相似的。可以从以下两点来区分两者:建设模式着重于慢慢将组件装配成一个制品并向外提供制品,而抽象工场模式着重于获得产物族中相关的多个产物工具;抽象工场模式的应用是受限于产物族的(详细拜见《深入浅出工场模式》),制作模式则不会。
由于制作模式和抽象工场模式在实现成果上相似,所以两者利用的情况都较量巨大而且需要更多的机动性。 制作模式中大概要利用到差异“巨细”的组件类,因此这时也常常和合成模式在一起利用。