Effctive java 笔记(一)考虑使用静态工厂方法替代构造方法

考虑使用静态工厂方法替代构造方法

1. 创建对象

什么是静态工厂方法

在 Java 中,获得一个类实例最简单的方法就是使用 new 关键字,通过构造函数来实现对象的创建。
eg:

Dog dog=new Dog();

Date date=new Date();

而静态工厂方法:

 Calendar calendar = Calendar.getInstance();
  Integer number = Integer.valueOf("3");
  

像这样,不通过new关键字,通过一个静态方法得到类的实列的方法就是静态工厂方法。

2. 静态工厂方法和实例工厂方法和工厂模式

静态工厂方法:

就是直接可以通过静态方法来实例化一个对象

public class Car{
    public static Car newtInstance(){
        return new Car();
    }
}
Car .newtInstance();

创建 Car对象直接调用Car类的静态方法newtInstance方法来进行实现

实例工厂方法:

就是先创建类对象,然后通过对象来调用创建实例对象的方法

public class CarFactory {
    public Car newtInstance(){
        return new Car();
    }
}
CarFactory  carFactory  =new CarFactory();
carFactory.newtInstance();

工厂模式

静态工厂方法通常指的是某个类里的静态方法,通过调用该静态方法可以得到属于该类的一个实例;

工厂模式是一种设计模式。具体看设计模式。

如果要说相似的话,静态工厂方法跟简单工厂模式倒有那么点像,不过区别也挺大,简单工厂模式里的静态工厂方法会创建各种不同的对象(不同类的实例),而静态工厂方法一般只创建属于该类的一个实例(包括子类);

3. 使用静态工厂方法的优点

1.有名字,可读性更强

由于语言的特性,Java 的构造函数都是跟类名一样的。这导致的一个问题是构造函数的名称不够灵活,经常不能准确地描述返回值,在有多个重载的构造函数时尤甚,如果参数类型、数目又比较相似的话,那更是很容易出错。

eg:

Date date2 = new Date("0");
Date date3 = new Date(1,2,1);

Date 类有很多重载函数,我们发现,可读性差,不查文档,不看注释很难知道其创建的对象的具体含义

2.与构造方法不同,它们不需要每次调用时都创建一个新对象

JDK中的Boolean类的valueOf方法可以很好的印证这个优势,在Boolean类中,有两个事先创建好的Boolean对象(True,False)

public final class Boolean implements java.io.Serializable,
                                      Comparable
{
    /**
     * The {@code Boolean} object corresponding to the primitive
     * value {@code true}.
     */
    public static final Boolean TRUE = new Boolean(true);

    /**
     * The {@code Boolean} object corresponding to the primitive
     * value {@code false}.
     */
    public static final Boolean FALSE = new Boolean(false);

当我们调用Boolean.valueOf(“true”)方法时,返回的就是这两个实例的引用,这样可以避免创建不必要的对象,如果使用构造器的话,就达不到这种效果了;

public static Boolean valueOf(String s) {
        return toBoolean(s) ? TRUE : FALSE;
    }

3.可以返回其返回类型的任何子类型的对象

Class Person {
    public static Person getInstance(){
        return new Person();
        // 这里可以改为 return new Player() / Cooker()
    }
}
Class Player extends Person{
}
Class Cooker extends Person{
}
public static Person getPlayer(){
        return new Player ();//或者return new Cooker();
    }
    

4.在创建带泛型的实例时,能使代码变得简洁

这条主要是针对带泛型类的繁琐声明而说的,需要重复书写两次泛型参数:

class MyMap {
    /**
     *
     */
    public MyMap()
    {

    }

    public static  MyMap newInstance(){
        return new MyMap();
    }
}
MyMap map1 = new MyMap();
//更加简洁,不需要重复指明类型参数,可以自行推导出来
 MyMap map2 = MyMap.newInstance();

不过自从 java7 开始,这种方式已经被优化过了 —— 对于一个已知类型的变量进行赋值时,由于泛型参数是可以被推导出,所以可以在创建实例时省略掉泛型参数。

Map map = new HashMap<>();

4. 使用静态工厂方法的缺点

1.如果类不含public或protect的构造方法,将不能被继承

如下类,不能被其它类继承

class MyMap {

    private MyMap()
    {

    }
    public static  MyMap newInstance(){
        return new MyMap();

    }
}

2.与其它普通静态方法没有区别,没有明确的标识一个静态方法用于实例化类

所以,一般一个静态工厂方法需要有详细的注释,遵守标准的命名,如使用getInstance、valueOf、newInstance等方法名;

下面是一些静态工厂方法的常用名称。以下清单并非完整:

  • from——A 类型转换方法,它接受单个参数并返回此类型的相应实例,例如:Date d = Date.from(instant);
    of——一个聚合方法,接受多个参数并返回该类型的实例,并把他们合并在一起,例如:Set faceCards = EnumSet.of(JACK, QUEEN, KING);
  • valueOf——from 和 to 更为详细的替代 方式,例如:BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
    instance 或 getinstance——返回一个由其参数 (如果有的话) 描述的实例,但不能说它具有相同的值,例如:StackWalker luke = StackWalker.getInstance(options);
  • create 或 newInstance——与 instance 或 getInstance 类似,除了该方法保证每个调用返回一个新的实例,例如:Object newArray = Array.newInstance(classObject, arrayLen);
  • getType——与 getInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型,例如:FileStore fs = Files.getFileStore(path);
  • newType——与 newInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型,例如:BufferedReader br = Files.newBufferedReader(path);
  • type—— getType 和 newType 简洁的替代方式,例如:List litany = Collections.list(legacyLitany);\

总之,静态工厂方法和公共构造方法都有它们的用途,并且了解它们的相对优点是值得的。通常,静态工厂更可取,因此避免在没有考虑静态工厂的情况下提供公共构造方法。

本文是根据Effctive java和网上部分博客总结而出。 侵删。

你可能感兴趣的:(Effctive,Java)