Effective Java 第三版读书笔记(创建和销毁对象1)

1.Java语言支持四种类型:

引用类型:类(包括Enum)、接口、数组

基本类型

2.方法签名由名称、所有参数类型组成;签名的方法不包含返回类型

一、创建和销毁对象

第1条.用静态工厂方法代替构造器

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

1.静态工厂方法与构造器不同的优势

1).它们有名称

比如在下面这种情况下,如果我们使用构造函数,在调用构造函数的时候很容易混淆两者。

public class Test {
    Test(int i, String s){

    }

    Test(String s, int i){

    }
}

2).不必每次调用它们的时候都创建一个新的对象。

3).它们可以返回原返回类型的任何子类型的对象。

按照惯例,接口Type的静态工厂方法被放在一个名为Types的不可实例化的伴生类中。例如,Java Collections Framework的集合接口中有45个工具实现,分别提供了不可修改的集合、同步集合,等。几乎所有这些实现都通过类java.util.Collections中导出。所有返回对象的类都是非公有的。

4).所返回的对象的类可以随着每次调用的变化而发生变化。(我理解这其实和优点3是一个意思)

5).方法返回的对象所属的类,在编写包含该静态工厂的类时可以不存在。(我理解这还是优点3带来的好处)

2.静态工厂方法与构造器不同的劣势

1).类如果不含公有的或者受保护的构造器,就不能被子类化。

2).很难发现。

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

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

假设我们需要表示营养成分表,其中有几个域是必须的,还有超过20个可选域,通常情况下我们会采用重叠构造器的模式。

package com.example.ownlearn;

import lombok.Data;

@Data
public class Nutrition {
    //必填
    private final int servingSize;
    private final int servings;
    
    //选填
    private final int calories;
    private final int fat;

    
    public Nutrition(int servingSize,int servings) {
        this(servingSize,servings,0,0);
    }

    public Nutrition(int servingSize, int servings, int calories){
        this(servingSize,servings,calories,0);
    }
    
    public Nutrition(int servingSize, int servings, int calories, int fat) {
        this.servingSize = servingSize;
        this.servings = servings;
        this.calories = calories;
        this.fat = fat;
    }

}

这种方式可行,但是我们可以看到并没有只给servingSize、servings、fat赋值的构造方法,这意味着我们还是要调用最后一个构造函数,这导致我们需要给某些我们并不想设置的参数传递值,如果我们有大量参数,那么这种方式就会变得不那么好。

我们还有第二种方式,JavaBean模式,我们先调用一个无参的构造器来创建对象,然后再调用setter方法为每个参数赋值。这种方式存在的问题是,因为构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的对象将会导致失败。

第三种方式,建造者模式,既能保证像重叠构造器模式那样的安全性,也能保证像JavaBean那样的可读性。

package com.example.ownlearn;

public class NutritionFact {
    //必填
    private final int servingSize;
    private final int servings;

    //选填
    private final int calories;
    private final int fat;

    public static class Builder{
        //必填
        private final int servingSize;
        private final int servings;

        //选填
        private final int calories = 0;
        private final int fat = 0;

        public Builder(int servingSize,int servings){
            this.servings = servings;
            this.servingSize = servingSize;
        }


        public Builder calories(int calories){
            calories = calories;
            return this;
        }

        public Builder fat(int fat){
            fat = fat;
            return this;
        }

        public NutritionFact build(){
            return new NutritionFact(this);
        }
    }

    public NutritionFact (Builder builder){
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
    }




}

我们这样调用

NutritionFact nutritionFact = new NutritionFact.Builder(1,1).fat(1).build();

如果我们的类为父类,我们可以这样来实现。

package com.example.ownlearn;

import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;

public class Pizza {
    public enum Topping {HAM,HUSHROOM,ONION,PEPPER,SAUSAGE}
    final Set<Topping> toppings;

    abstract static class Builder<T extends Builder<T>>{
        EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
        public T addTopping(Topping topping){
            toppings.add(Objects.requireNonNull(topping));
            return self();
        }

        abstract Pizza build();

        protected abstract T self();
    }

    Pizza(Builder<?>builder){
        toppings = builder.toppings.clone();
    }
}
package com.example.ownlearn;

public class Calzone extends Pizza {

    private final boolean sauceinside;

    public static class Builder extends Pizza.Builder<Builder>{

        private boolean sauceinside = false;

        public Builder sauceInside(){
            sauceinside = true;
            return this;
        }

        @Override
        Calzone build() {
            return new Calzone(this);
        }

        @Override
        protected Builder self() {
           return this;
        }
    }

    Calzone(Builder builder) {
        super(builder);
        this.sauceinside = builder.sauceinside;
    }
}

 

package com.example.ownlearn;

import java.util.Objects;

public class NyPizza extends Pizza {

    public enum  Size{SMALL}
    private final Size size;

    public static class Builder extends Pizza.Builder<Builder>{
        private final Size size;

        public Builder(Size size){
            this.size = Objects.requireNonNull(size);
        }

        @Override
        public NyPizza build() {
            return new NyPizza(this);
        }

        @Override
        protected Builder self() {
            return this;
        }
    }

    NyPizza(Builder builder) {
        super(builder);
        size = builder.size;
    }
}

我们这样调用 

NyPizza nyPizza = new NyPizza.Builder(SMALL).addTopping(Pizza.Topping.SAUSAGE).build();
Calzone calzone = new Calzone.Builder().addTopping(Pizza.Topping.HAM).sauceInside().build();
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值