zoukankan      html  css  js  c++  java
  • builder模式的新学习

    builder模式的新学习

    静态工厂和构造器有个共同的局限性:他们不能很好的扩展到大量的可选参数。大多数产品在牧歌可选与中都会有非零的值

    对于这种类,应该使用哪种构造器或者静态方法来进行编写?程序员一般习惯采用重叠构造器(telescoping constructor)模式。在这种模式下,你可以第一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个有两个可选参数,以此类推,最后一个构造器包含所有的可选参数。

    public class NutritionFacts {
        private final int servingSize;  //required
        private final int servings;     //required
        private final int calories;     //optional
        private final int fat;          //optional
        private final int sodium;       //optional
        private final int carbohydrate; //optional
        
        public NutritionFacts(int servingSize,int servings){
            this(servingSize,servings,0);
        }
        public NutritionFacts(int servingSize,int servings,int calories){
            this(servingSize,servings,calories,0);
        }
        public NutritionFacts(int servingSize,int servings,int calories,int fat){
            this(servingSize,servings,calories,fat,0);
        }
        public NutritionFacts(int servingSize,int servings,int calories,int fat,int sodium){
            this(servingSize,servings,calories,fat,sodium,0);
        }
        public NutritionFacts(int servingSize,int servings,int calories,int fat,int sodium,int carbohydrate){
            this.servingSize = servingSize;
            this.servings = servings;
            this.calories = calories;
            this.fat = fat;
            this.sodium = sodium;
            this.carbohydrate = carbohydrate;
        }
    }
    

    当我们想要穿件实例的时候,就利用参数列表最短的构造器,但是该列表包含了要设置的所有参数:

    NutritionFacts cocaCloa = new NutritionFacts(240,8,100,0,35,27);
    

    这个构造器通常需要许多你本不想设置的参数,但是不能不为它传递值。在这个例子中,我们给fat传递了一个值为0。如果“仅仅”只有6个参数,看起来并不算太早,问题是随着参数数目的增加,它很快就会失去控制。

    使用JavaBean模式,也能够代替这种问题。遗憾的是在一定的情况下,我们需要额外的努力来保证它的安全性。

    幸运的是,还有新的替代方法,既能够保证向重叠构造器模式那样安全,也能够保证像JavaBean模式的那么好的可读性。这就是Builder模式的一种形式。不直接生成想要的对象。然后客户端利用所有必要的参数调用构造器(或者静态工厂),得到一个builder对象。然后客户端在builder对象上调用类似于setting的方法,来设置每个相关的可选参数。最后,客户端调用午餐的build方法来生成不可变的对象。这个builder是他构建的类的静态成员类。

    //Builder Pattern
    public class NutritionFacts{
        private final int servingSize;  //required
        private final int servings;     //required
        private final int calories;     //optional
        private final int fat;          //optional
        private final int sodium;       //optional
        private final int carbohydrate; //optional
        
        public static class Builder{
            private final int servingSize;  //required
            private final int servings;     //required
            private int calories;     //optional
            private int fat;          //optional
            private int sodium;       //optional
            private int carbohydrate; //optional
            
            public Builder(int servingSize,int servings){
                this.servingSize = servingSize;
                this.servings = servings;
            }
            public Builder calories(int val){
                this.calories = val;
                return this;
            }
            public Builder fat(int val){
                this.fat = val;
                return this;
            }
            public Builder sodium(int val){
                this.sodium = val;
                return this;
            }
            public Builder carbohydrate(int val){
                this.carbohydrate = val;
                return this;
            }
            public NutritionFacts build(){
                return new NutritionFacts(this);
            }
        }
        private NutritionFacts(Builder builder){
            this.servingSize = builder.servingSize;
            this.servings = builder.servings;
            this.calories = builder.calories;
            this.fat = builder.fat;
            this.sodium = builder.sodium;
            this.carbohydrate = builder.carbohydrate;
        }
    }
    

    注意NutrtionFacts是不可变的,所有的默认参数都是单独放在一个地方。builder的setter方法返回builder本身,以便可以把调用连接起来。

    NutritionFacts nutritionFacts = 
        new NutritionFacts.Builder(240, 8)
    	.calories(100)
    	.sodium(35)
    	.carbohydrate(27)
    	.build();
    

    这样的调用客户端代码很容易编写,更为重要的是易于阅读。

    build方法可以检验这些约束条件。将参数从builder拷贝到对象中之后,并在对象域而不是builder域中对他们进行检验。如果违反了约束条件,build方法就应该抛出IllegalStateException。

    Builder 模式自身的不足。为了创建对象,必须先创建它的构造器。虽然创建构造器的开销在实践中可能并不明显,但是在某些十分注重性能的情况下,可能就成问题了。

    Builder 模式还比重叠构造器模式更加冗长,因此它只能在有很多参数的时候才使用。比如4个或者更多的参数。但是记住,将来你可能添加参数。如果一开始就是用构造器或者静态工厂,等类需要更多的参数时才添加构造器就会无法控制,那些过时的构造器或者静态工厂显得十分的不协调。因此,通常最好一开始就是用构造器。

    简而言之,如果类的构造器或者静态工厂中具有多个参数,设计这种类的时,Builder模式就是种不错的选择,特别是当大多数的参数都是可选的时候。

  • 相关阅读:
    终极快速排序
    微服务(Microservices)【翻译】
    从Uber微服务看最佳实践如何炼成?
    请不要在“微服务”的狂热中迷失自我!
    笔记_第四章_04
    笔记_第三章_03
    笔记_第二章_02
    笔记_第一章_01
    jQuery简单入门(五)
    jQuery简单入门(四)
  • 原文地址:https://www.cnblogs.com/mr-cc/p/5772980.html
Copyright © 2011-2022 走看看