《Effective java》读书记录-第1条-考虑用静态工厂方法代替构造器

本文探讨了静态工厂方法相较于构造器的优点,包括更好的命名、对象复用、子类型灵活性及简化参数化类型实例创建等。同时指出了其不足之处,如无法被子类化和与其他静态方法难以区分的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

获取一个实例的方法有两种:

1.就是提供一个公有的构造器。

2.提供一个公有的静态工厂方法,它只是一个返回类的实例的静态方法。

注意:静态工厂方法与设计模式中的工厂方法模式不同。


静态工厂方法对于构造器具有以下一些优势。

1.静态工厂方法有名称。

构造器没有名称,不利于描述返回结果,只能通过其参数去猜测返回的实例所具有的属性。而如果用静态工厂方法就可以通过方法名来突出它们之间的区别。

public class Number1 {

    private int number;
    /**
     * Number1构造方法
     * number属性为1
     */
    public Number1 () {
        this.number=1;
    }
    /**
     * Number1构造方法
     * balance==true,number属性设置为2
     */
    public Number1 (boolean balance) {
        if (balance) this.number=2;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }
}
public class Number2 {
    private int number;

    public static Number2 getOne(){
        Number2 number=new Number2();
        number.setNumber(1);
        return number;
    }

    public static Number2 getTwo(){
        Number2 number=new Number2();
        number.setNumber(2);
        return number;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }
}
public class NumberTest extends TestCase {
    public void test(){
        Number1 number1=new Number1();
        System.out.println(number1.getNumber());
        number1=new Number1(true);
        System.out.println(number1.getNumber());

        Number2 number2=Number2.getOne();
        System.out.println(number2.getNumber());
        number2=Number2.getTwo();
        System.out.println(number2.getNumber());
    }
}


在单元测试代码中Number2通过静态工厂方法获取到的返回对象的代码,比Number1通过构造方法获取到的返回对象更容易阅读。

2.静态工厂方法不必在每次调用它们的时候都创建一个新对象。

静态工厂方法使得不可变类可以预先构建好的实例,或者将构建好的实例缓存起来,进行重复使用。如果程序经常请求创建相同的对象,并且创建对象的代价很高,这项技术可以极大地提升性能。

静态工厂方法能够为重复的调用返回相同对象,这样有助于类总能严格控制在某个时刻哪些实例应该存在(实例受控的类instance-controlled)。

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


3.静态工厂方法可以返回原返回类型的任何子类型的对象。

静态工厂方法可以让我们在返回对象的类时,有更大的灵活性。这种方式使得API可以返回非公的有类对象。

如EnumSet类就采用了这种方式,当<=64的时候返RegularEnumSet其他的情况就返回JumboEnumSet

public class EnumSet{
    public static <E extends Enum<e>> EnumSet<e> noneOf(Class<e> elementType) {
        Enum<?>[] universe = getUniverse(elementType);
        if (universe == null)
            throw new ClassCastException(elementType + " not an enum");

        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }
}

在Java Collections Framework的集合接口有32个便利实现,分别提供了不可修改的集合,同步集合等等。几乎所有这些实现都通过静态工厂方法在一个不可实例化的类(java.util.Collections)中导出。所有返回对象的类都是非公有的。

public class Collections{
    public static <e> Set<e> checkedSet(Set<e> s, Class<e> type) {
        return new CheckedSet<>(s, type);
    }

    /**
     * @serial include
     */
    static class CheckedSet<e> extends CheckedCollection<e> implements Set<e>, Serializable{
        private static final long serialVersionUID = 4694047833775013803L;
        CheckedSet(Set<e> s, Class<e> elementType) { super(s, elementType); }
        public boolean equals(Object o) { return o == this || c.equals(o); }
        public int hashCode()           { return c.hashCode(); }
    }
}


4.静态工厂方法在创建参数化类型实例的时候,它们使代码变得更加简洁。


缺点

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

例如,想要将Collections中的任何方便的实现类子类化,这是不可能的。但是这样也许会因祸得福,因为它鼓励程序员使用复合(composition),而不是继承。

2.它们与其他的静态方法实际上没有任何区别。

目前它们不会像构造器那样在API文档中明确标识出来,对于那些提供了静态工厂方法而不是构造器的类来说,想要查明如何实例化一个类,是非常困难的。

你可以通过在类或者接口注释中关注静态工厂,并准守标准的命名习惯。下面是静态工厂方法的一些习惯名称。

valueOf:不太严格的说,该方法返回的实例与它的参数具有相同的值。这样的静态工厂方法实际上是类型转换方法。

of:valueOf的一种更为简洁的替代,在EnumSet中使用并流行起来。

getInstance:返回的实例是通过方法的参数来描述的,但是不能够说与参数具有同样的值。对于Singleton来说,该方法没有参数,并返回唯一的实例。

newInstance:像getInstance一样,但newInstance能够确保返回的每个实例都与所有其他实例不同。

getType:像getInstance一样,但是在工厂方法处于不同的类中的时候使用,Type表示工厂方法所返回的对象类型。

newType:像newInstance一样,但是在工厂方法处于不同的类中的时候使用。Type表示工厂方法所返回的对象类型。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值