java设计模式之建造者模式学习
1 概述
建造者模式(builder pattern)主要用于“分步骤构建一个复杂的对象”,在这其中“分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化。因此, 建造者模式主要用来解决“对象部分”的需求变化。 这样可以对对象构造的过程进行更加精细的控制。
2 示例
以生产手机为例,每个手机分为屏幕screen、cpu、battery。现在要生产两种手机,苹果机和三星。
苹果:
package org.scott.builder.before.use;
import java.util.arraylist;
import java.util.list;
/**
* @author scott
* @version 2013-11-20
* @description
*/
public class applephone {
list<string> parts = new arraylist<string>();
public void createcpu() {
parts.add("cup: qualcomm");
}
public void createscreen() {
parts.add("screen: jdi");
}
public void createbattery() {
parts.add("battery: desai");
}
public void show(){
system.out.print("产品部件信息:");
for(string part : parts){
system.out.print(part + "\t");
}
}
}
三星:
package org.scott.builder.before.use;
import java.util.arraylist;
import java.util.list;
/**
* @author scott
* @version 2013-11-20
* @description
*/
public class samsungphone {
list<string> parts = new arraylist<string>();
public void createcpu() {
parts.add("cup: mtk");
}
public void createscreen() {
parts.add("screen: samsung");
}
public void createbattery() {
parts.add("battery: desai");
}
public void show(){
system.out.print("产品部件信息:");
for(string part : parts){
system.out.print(part + "\t");
}
}
}
测试客户端:
package org.scott.builder.before.use;
/**
* @author scott
* @version 2013-11-20
* @description
*/
public class builertest {
private static applephone iphone = new applephone();
private static samsungphone samphone = new samsungphone();
public static void main(string args[]){
iphone.createcpu();
iphone.createscreen();
iphone.createbattery();
iphone.show();
samphone.createcpu();
samphone.createscreen();
samphone.createbattery();
samphone.show();
}
}
是不是发现个问题?那就是生产手机的每一道工序都是一样的,确切的说是工序名称一样,只是具体的每个工序的处理不同,工序是不变的,就这么几步,每道工序的具体处理是变化的,由此,我们可以把不变的抽取出来,以“不变应万变”,将变化的,交给具体的产品来做。
具体怎么做?这回的builder模式派上用场了。
首先来个phone的接口:
package org.scott.builder.after.use;
import java.util.arraylist;
import java.util.list;
/**
* @author scott
* @version 2013-11-20
* @description
*/
public abstract class phone {
protected list<string> parts = new arraylist<string>();
public void add(string part){
parts.add(part);
}
public void show(){
system.out.print("产品部件信息:");
for(string part : parts){
system.out.print(part + "\t");
}
}
}
苹果手机类:
package org.scott.builder.after.use;
/**
* @author scott
* @version 2013-11-20
* @description
*/
public class applephone extends phone{
}
三星手机类:
package org.scott.builder.after.use;
/**
* @author scott
* @version 2013-11-20
* @description
*/
public class samsungphone extends phone{
}
再定义个生产步骤的接口builder:
package org.scott.builder.after.use;
/**
* @author scott
* @version 2013-11-20
* @description
*/
public interface builder {
public void buildcpu();
public void buildscreen();
public void buildbattery();
public phone getphone();
}
苹果手机的builder:
package org.scott.builder.after.use;
/**
* @author scott
* @version 2013-11-20
* @description
*/
public class applephonebuilder implements builder{
private phone phone = new applephone();
@override
public void buildcpu() {
phone.add("cup: qualcomm");
}
@override
public void buildscreen() {
phone.add("screen: jdi");
}
@override
public void buildbattery() {
phone.add("battery: desai");
}
@override
public phone getphone() {
return phone;
}
}
三星手机的builder:
package org.scott.builder.after.use;
/**
* @author scott
* @version 2013-11-20
* @description
*/
public class samsungphonebuilder implements builder{
private phone phone = new samsungphone();
@override
public void buildcpu() {
phone.add("cup: mtk");
}
@override
public void buildscreen() {
phone.add("screen: samsung");
}
@override
public void buildbattery() {
phone.add("battery: desai");
}
@override
public phone getphone() {
return phone;
}
}
指导具体生产手机的director:
package org.scott.builder.after.use;
/**
* @author scott
* @version 2013-11-20
* @description
*/
public class director {
private builder builder;
public director(builder builder){
this.builder = builder;
}
public void construct(){
builder.buildcpu();
builder.buildscreen();
builder.buildbattery();
}
}
最后写个测试类:
package org.scott.builder.after.use;
/**
* @author scott
* @version 2013-11-20
* @description
*/
public class buildertest {
private static builder iphonebuilder = new applephonebuilder();
private static builder samphonebuilder = new samsungphonebuilder();
public static void main(string[] args) {
director director = new director(iphonebuilder);
director.construct();
phone phone = iphonebuilder.getphone();
system.out.println("iphone");
phone.show();
director = new director(samphonebuilder);
director.construct();
phone = samphonebuilder.getphone();
system.out.println("\nsamsung");
phone.show();
}
}
运行结果:
iphone
产品部件信息:cup: qualcomm screen: jdi battery: desai
samsung
产品部件信息:cup: mtk screen: samsung battery: desai
这里的两个phone实体类是空的,如果是这种情况,那么它们可以省略掉,如果 phone接口也可以被省略掉,最终剩下的就只有 director、builder、和具体的 bulider 实现类。并且,applephone类和 samsungphone类是有关系的两个类,它们不同的手机品牌,如果遇到两个或多个没有太多关系的类,公共的接口phone就没有存在的必要,但是这时候,那么 builder 接口的规定的 getphone() 方法的返回值怎么确定呢?
无论返回值类型是 applephone还是samsungphone,都会产生问题,因为返回结果的类型不统一。此时,可以将 phone定义成一个空接口(不包含任何方法的接口),再让这些没有相互关系的具体产品类都去实现这个接口,那么 builder 接口里面规定的 getphone() 方法的返回值类型依然是 phone 类型,就解决问题了。不过这种情况下,也就没有使用builder模式的必要了。