zoukankan      html  css  js  c++  java
  • Effective Java2读书笔记创建和销毁对象(一)

    第1条:考虑用静态工厂方法代替构造器

    通常情况下,我们创建一个对象采取new的形式,但是还有一种方法也是经常使用到的,它的名称叫做静态工厂方法

    例如,java中基本类型boolean的包装类Boolean就采用了这种方式,源代码如下:

        public static Boolean valueOf(boolean b) {
            return (b ? TRUE : FALSE);
        }

    当然,除了valueOf这种比较low的名字之外,我们常用的还有getInstance(最常见),newInstance,getType等。

    静态工厂方法相对于构造器,好处多多。

    ①静态工厂方法有名称,而构造器是固定的。

    例如,BigInteger的构造方法返回一个数字。如果想返回一个随机素数,用名为BigInteger.probablePrime的静态方法表示显然会更加清晰易读。

    ②不必每次调用的时候都创建一个新的对象。

    这使得不可变类可以使用预先构建好的实例,或者将构建好的实例缓存起来重复利用,从而避免创建不必要的重复对象。例如上例中的Boolean.valueOf(boolean b)方法,调用它时,它从来没有创建对象。

    ③它可以返回原返回类型的任何子类型对象。

    这里就不得不提及以下简单工厂模式,大家在平时开发中使用频率极高。

    例如,有物理型英雄和法术型英雄,想要根据传入的类型获取对应的英雄。

    public abstract class Hero {
    }
    
    public class APHero extends Hero {
        @Override
        public String toString() {
            return "法术型英雄";
        }
    }
    
    public class ADHero extends Hero {
        @Override
        public String toString() {
            return "物理型英雄";
        }
    }

    使用静态工厂方法就可以获取到指定的子类型,大大增加了可扩展性。

    public class HeroFactory {
        APHero ap = new APHero();
        ADHero ad = new ADHero();
        public Hero getHeroInstance(String type){
            switch(type){
                case "AP":return ap;
                case "AD":return ad;
                default: return null;
            }
        }
    }

    第2条:遇到多个构造器参数时考虑用构建器

    静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。

    有时候会碰到这样的情况,一个类里面属性很多,有些是必须的,有些是可选的。这样一来,普通的构造方法就得写一大堆(因为创建对象时可能性太多了)。

    还有一种方法也是我们最常用的,就是构造方法就用默认的,每个属性都添加get set方法(JavaBean)。这样创建一个实例很容易,代码也清晰很多。但遗憾的是JavaBean自身有很严重的缺点,因为构造过程被分到了若个个调用中,可能出现不一致状态,导致多线程操作时不安全。

    构建器方法既能保证安全性,又能保证可读性。下面大家来看一个例子(食品上的营养成分表):

    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 {
            // 必需参数
            private final int servingSize;
            private final int servings;
    
            // 不必需参数
            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;
            }
            //注意这里,跟Javabean很像,设置了一系列属性之后,Builder调用build方法构建真正的对象
            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;
        }
        
    }

    在客户端我们就可以使用类似于jquery中连缀的这种语法来创建对象了

        public static void main(String[] args) {
            NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
                    .calories(100).sodium(35).carbohydrate(27).build();
        }

    实际上,就相当于将NutritionFacts类将创建对象的功能委托给了静态内部类Builder。而且,因为static类本身是线程安全的,也避免了javabean的缺陷。

    作者: 张万帆
    欢迎任何形式的转载,但请务必注明出处。

  • 相关阅读:
    康拓展开
    P6032 选择客栈 加强版 递推
    0923考试T3 二进制,位运算
    0922考试T3 dfs序 lca 线段树 树上问题
    0921考试T2
    0922考试T1
    P3934 [Ynoi2016]炸脖龙I 树状数组 扩展欧拉定理
    0922考试T4 区间DP
    P6834 [Cnoi2020]梦原 树状数组 期望DP
    UVA1364 Knights of the Round Table Tarjan求点双联通分量+二分图染色
  • 原文地址:https://www.cnblogs.com/ZhangWanFan/p/5232617.html
Copyright © 2011-2022 走看看