• 设计模式之建造者模式


    1 概述

        建造者模式(Builder Pattern)主要用于“分步骤构建一个复杂的对象”,在这其中“分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化。因此, 建造者模式主要用来解决“对象部分”的需求变化。 这样可以对对象构造的过程进行更加精细的控制。

    2 示例

        还是以生产手机为例,每个手机分为屏幕Screen、CPU、Battery。现在要生产两种手机,苹果机和三星。

     苹果:

     1 package org.scott.builder.before.use;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 /** 
     7  * @author Scott
     8  * @version 2013-11-20 
     9  * @description
    10  */
    11 public class ApplePhone {
    12     List<String> parts = new ArrayList<String>();
    13     
    14     public void createCPU() {
    15         parts.add("CUP: Qualcomm");
    16     }
    17 
    18     public void createScreen() {
    19         parts.add("SCREEN: JDI");
    20     }
    21     
    22     public void createBattery() {
    23         parts.add("BATTERY: DeSai");
    24     }
    25     
    26     public void show(){
    27         System.out.print("产品部件信息:");
    28         for(String part : parts){
    29             System.out.print(part + "	");
    30         }
    31     }
    32 }

    三星:

     1 package org.scott.builder.before.use;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 /** 
     7  * @author Scott
     8  * @version 2013-11-20 
     9  * @description
    10  */
    11 public class SamsungPhone {
    12     List<String> parts = new ArrayList<String>();
    13     
    14     public void createCPU() {
    15         parts.add("CUP: MTK");
    16     }
    17 
    18     public void createScreen() {
    19         parts.add("SCREEN: Samsung");
    20     }
    21     
    22     public void createBattery() {
    23         parts.add("BATTERY: DeSai");
    24     }
    25     
    26     public void show(){
    27         System.out.print("产品部件信息:");
    28         for(String part : parts){
    29             System.out.print(part + "	");
    30         }
    31     }
    32 }

    测试客户端:

     1 package org.scott.builder.before.use;
     2 /** 
     3  * @author Scott
     4  * @version 2013-11-20 
     5  * @description
     6  */
     7 public class BuilerTest {
     8     private static ApplePhone iphone = new ApplePhone();
     9     private static SamsungPhone samPhone = new SamsungPhone();
    10     
    11     public static void main(String args[]){
    12         iphone.createCPU();
    13         iphone.createScreen();
    14         iphone.createBattery();
    15         iphone.show();
    16         
    17         samPhone.createCPU();
    18         samPhone.createScreen();
    19         samPhone.createBattery();
    20         samPhone.show();
    21     }
    22 }

      是不是发现个问题?那就是生产手机的每一道工序都是一样的,确切的说是工序名称一样,只是具体的每个工序的处理不同,工序是不变的,就这么几步,每道工序的具体处理是变化的,由此,我们可以把不变的抽取出来,以“不变应万变”,将变化的,交给具体的产品来做。

      具体怎么做?这回的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 + "	");
            }
        }
    }

    苹果手机类:

    1 package org.scott.builder.after.use;
    2 /** 
    3  * @author Scott
    4  * @version 2013-11-20 
    5  * @description
    6  */
    7 public class ApplePhone extends Phone{
    8 
    9 }

    三星手机类:

    1 package org.scott.builder.after.use;
    2 /** 
    3  * @author Scott
    4  * @version 2013-11-20 
    5  * @description
    6  */
    7 public class SamsungPhone extends Phone{
    8 
    9 }

    再定义个生产步骤的接口Builder:

     1 package org.scott.builder.after.use;
     2 /** 
     3  * @author Scott
     4  * @version 2013-11-20 
     5  * @description
     6  */
     7 public interface Builder {
     8     public void buildCPU();
     9     
    10     public void buildScreen();
    11     
    12     public void buildBattery();
    13     
    14     public Phone getPhone();
    15 }

    苹果手机的Builder:

     1 package org.scott.builder.after.use;
     2 /** 
     3  * @author Scott
     4  * @version 2013-11-20 
     5  * @description
     6  */
     7 public class ApplePhoneBuilder implements Builder{
     8     private Phone phone = new ApplePhone();
     9     
    10     @Override
    11     public void buildCPU() {
    12         phone.add("CUP: Qualcomm");
    13     }
    14 
    15     @Override
    16     public void buildScreen() {
    17         phone.add("SCREEN: JDI");
    18     }
    19 
    20     @Override
    21     public void buildBattery() {
    22         phone.add("BATTERY: DeSai");
    23     }
    24 
    25     @Override
    26     public Phone getPhone() {
    27         return phone;
    28     }
    29 
    30 }

    三星手机的Builder:

     1 package org.scott.builder.after.use;
     2 /** 
     3  * @author Scott
     4  * @version 2013-11-20 
     5  * @description
     6  */
     7 public class SamsungPhoneBuilder implements Builder{
     8     
     9     private Phone phone = new SamsungPhone();
    10     
    11     @Override
    12     public void buildCPU() {
    13         phone.add("CUP: MTK");        
    14     }
    15 
    16     @Override
    17     public void buildScreen() {
    18         phone.add("SCREEN: Samsung");
    19     }
    20 
    21     @Override
    22     public void buildBattery() {
    23         phone.add("BATTERY: DeSai");        
    24     }
    25 
    26     @Override
    27     public Phone getPhone() {
    28         return phone;
    29     }
    30 
    31 }

    指导具体生产手机的Director:

     1 package org.scott.builder.after.use;
     2 /** 
     3  * @author Scott
     4  * @version 2013-11-20 
     5  * @description
     6  */
     7 public class Director {
     8     private Builder builder;
     9     
    10     public Director(Builder builder){
    11         this.builder = builder;
    12     }
    13     
    14     public void construct(){
    15         builder.buildCPU();
    16         builder.buildScreen();
    17         builder.buildBattery();
    18     }
    19 }

      最后写个测试类:

     1 package org.scott.builder.after.use;
     2 /** 
     3  * @author Scott
     4  * @version 2013-11-20 
     5  * @description
     6  */
     7 public class BuilderTest {
     8 
     9     private static Builder iPhoneBuilder = new ApplePhoneBuilder();
    10     private static Builder samPhoneBuilder  = new SamsungPhoneBuilder();
    11     
    12     public static void main(String[] args) {
    13         Director director = new Director(iPhoneBuilder);
    14         director.construct();
    15         Phone phone = iPhoneBuilder.getPhone();
    16         System.out.println("iphone");
    17         phone.show();
    18         
    19         director = new Director(samPhoneBuilder);
    20         director.construct();
    21         phone = samPhoneBuilder.getPhone();
    22         System.out.println("
    samSung");
    23         phone.show();
    24     }
    25 
    26 }

    运行结果:

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

      是不是看着和工厂模式也有点那么类似?工厂模式是对象之间的,是以对象为处理单位,而建造模式是深入到了对象的内部,以对象生产的步骤作为处理单位。这是我的理解,若是不准确,可以一起讨论讨论~

      最后来个经典的建造模式的UML图吧:

  • 相关阅读:
    Java1.7的HashMap源码分析-面试必备技能
    Springboot集成Swagger2
    springsecurity简单学习
    Java8的新特性
    HttpClient
    Filter的使用
    Spring拦截器和SpringAop实现
    运维工程师打怪升级进阶之路 V2.0
    欢迎加入微信交流群交流
    赞!7000 字学习笔记,一天搞定 MySQL
  • 原文地址:https://www.cnblogs.com/Scott007/p/3434470.html
Copyright © 2020-2023  润新知