zoukankan      html  css  js  c++  java
  • Effective Java 的笔记(二)

    书接上文。

    一、当构造函数过多的时候,请使用bulider模式。

    先说一下场景,有一个类,有许多的字段需要在new出object的时候就初始化。

    先看下一个恶心的代码吧,我始终认为,只有知道什么是丑,才能懂得什么是美。

    public class NutritionFacts {
        private final int servingSize;   // (mL)            required
        private final int servings;      // (per container) required
        private final int calories;      //                 optional
        private final int fat;           // (g)             optional
        private final int sodium;        // (mg)            optional
        private final int carbohydrate;  // (g)             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;
        }
    
        public static void main(String[] args) {
            NutritionFacts cocaCola =
                new NutritionFacts(240, 8, 100, 0, 35, 27);
        }
    }

    你可以想象在构造该对象的弟兄边写代码边骂的情形吗?

    下面我们用JavaBean的模式改变一下

    public class NutritionFacts {
        // Parameters initialized to default values (if any)
        private int servingSize  = -1;  // Required; no default value
        private int servings     = -1;  //     "     "     "      "
        private int calories     = 0;
        private int fat          = 0;
        private int sodium       = 0;
        private int carbohydrate = 0;
    
        public NutritionFacts() { }
    
        // Setters
        public void setServingSize(int val)  { servingSize = val; }
        public void setServings(int val)     { servings = val; }
        public void setCalories(int val)     { calories = val; }
        public void setFat(int val)          { fat = val; }
        public void setSodium(int val)       { sodium = val; }
        public void setCarbohydrate(int val) { carbohydrate = val; }
    
    
        public static void main(String[] args) {
            NutritionFacts cocaCola = new NutritionFacts();
            cocaCola.setServingSize(240);
            cocaCola.setServings(8);
            cocaCola.setCalories(100);
            cocaCola.setSodium(35);
            cocaCola.setCarbohydrate(27);
        }
    }

    不幸的是,JavaBean模式也有问题。很明显,这个类的字段不能定义为final类型的,导致如果该object对象运行在多线程环境,需要倍加的小心。

    对于final的定义:原始类型在运行期不能被改变,引用类型对引用的对象不能被改变,但是引用对象的值如果不是final的,是可以改变的。

    下面我们看看使用builder模式如何解决这个问题。

    首先看看bulider模式的定义(摘自GoF):

    (1) 意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

    (2) 适用性:当同时满足以下情况的时候可以使用Builder模式
        a. 当创建复杂对象的算法应该独立于该对象的组成部分以及他们的装配方式
        b. 当构造过程必须允许构造的对象有不同的表示

    看上去是不是头晕,大师说的话就是精炼,所谓“微言大义”嘛,好吧,那就深入的看看到底什么是builder模式。注,下面部分内容引用了这里还有这里,更加详细的内容请移步。

    类图:

    image

    协作图:

    image

    在建造复杂对象的过程中,具体的细节变化被封装到ConcreateBuilder中,具体构造的变化被封装到Director中。

    具体通过上面的例子看看builder模式的应用。

    public class NutritionFacts {
        private final int servingSize;
        private final int servings;
        private final int calories;
        private final int fat;
        private final int sodium;
        private final int carbohydrate;
    
        public static class Builder {
            // Required parameters
            private final int servingSize;
            private final int servings;
    
            // Optional parameters - initialized to default values
            private int calories      = 0;
            private int fat           = 0;
            private int carbohydrate  = 0;
            private int sodium        = 0;
    
            public Builder(int servingSize, int servings) {
                this.servingSize = servingSize;
                this.servings    = servings;
            }
    
            public Builder calories(int val)
                { calories = val;      return this; }
            public Builder fat(int val)
                { fat = val;           return this; }
            public Builder carbohydrate(int val)
                { carbohydrate = val;  return this; }
            public Builder sodium(int val)
                { sodium = val;        return this; }
    
            public NutritionFacts build() {
                return new NutritionFacts(this);
            }
        }
    
        private NutritionFacts(Builder builder) {
            servingSize  = builder.servingSize;
            servings     = builder.servings;
            calories     = builder.calories;
            fat          = builder.fat;
            sodium       = builder.sodium;
            carbohydrate = builder.carbohydrate;
        }
    
        public static void main(String[] args) {
            NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
                calories(100).sodium(35).carbohydrate(27).build();
        }
    }
     
  • 相关阅读:
    DotNet 获取所有 SQL Server 的数据库实例名称
    SQL Server 2008 R2 导出数据脚本的方法
    使用 Jquery 获取 Internet Explorer 浏览器版本
    OpenCV(EmguCV)2.1新特性介绍之图像差异StereoSGBM与设置窗口属性SetWindowProperty(StereoSGBM Of OpenCV 2.1)
    OpenCV(EmguCV)2.1新特性介绍之图像分割GrabCut(GrabCut Of OpenCV 2.1)
    背景建模与前景检测之三(Background Generation And Foreground Detection Phase 3)
    使用Lingobit Localizer汉化.net程序(Translate .net program using Lingobit Localizer)
    返修&售后服务管理网站设计与源码
    解决Windows7无法安装SP1补丁包及无法显示Windows功能列表的方法
    javascript获取到textarea文本框中的回车换行符
  • 原文地址:https://www.cnblogs.com/sodmecai/p/2508077.html
Copyright © 2011-2022 走看看