欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java设计模式之建造者模式学习

程序员文章站 2024-02-15 20:01:04
1 概述建造者模式(builder pattern)主要用于“分步骤构建一个复杂的对象”,在这其中“分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化。因此, 建造者...

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模式的必要了。