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模式就是种不错的选择,特别是当大多数的参数都是可选的时候。

  • 相关阅读:
    Construct Binary Tree from Preorder and Inorder Traversal
    Construct Binary Tree from Inorder and Postorder Traversal
    Maximum Depth of Binary Tree
    Sharepoint 2013 创建TimeJob 自动发送邮件
    IE8 不能够在Sharepoint平台上在线打开Office文档解决方案
    TFS安装与管理
    局域网通过IP查看对方计算机名,通过计算机名查看对方IP以及查看在线所有电脑IP
    JS 隐藏Sharepoint中List Item View页面的某一个字段
    SharePoint Calculated Column Formulas & Functions
    JS 两个一组数组转二维数组
  • 原文地址:https://www.cnblogs.com/mr-cc/p/5772980.html
Copyright © 2011-2022 走看看