Java 静态工厂方法详解

Java 静态工厂方法详解

本文章主要是对《Effective Java》对静态工厂方法的理解

第一次使用静态工厂方法是在HIT《Software Construction》课程的Lab2-P1的Graph.java中,对静态工厂方法的理解也相当有限,因此撰写此博客加深对静态工厂方法的理解。

Java 静态工厂方法在实际开发中经常使用,在《Effective Java》中第二章第一条即为:考虑使用静态工厂方法代替构造器。

静态工厂方法的含义

静态工厂方法指的是在类中提供一个公有的静态方法,返回类的一个实例。

静态工厂方法的第一大优势:它们有名称

类的构造器名称被限制为类名,然而当构造器因不同的参数类型而无法确切的描述被返回的对象时,静态工厂方法却可以提供不同的函数名称作为不同构造方法。
例如如下代码:

public class Person {
    private final SEX sex;
    private final String name;
    private final int age;

    private Person(String name, int age, SEX sex){
        this.sex = sex;
        this.name = name;
        this.age = age;
    }

    public static Person getManInstance(String name, int age){
        return new Person(name, age, SEX.man);
    }
    
    public static Person getWomanInstance(String name, int age){
        return new Person(name, age, SEX.woman);
    }
}

enum SEX{
    man,
    woman;
}

在实际开发中,也如果是需要定义相同参数的构造器,可以通过交换参数位置的方法完成,但是这并不是一个好的方法,降低客户端代码的阅读性。

静态工厂方法的第二大优势:不必在每次调用时都创建新的对象

这种方法使得immutable的类可以使用预先构造好的实例或者是已经构造好的静态实例对象、进行重复利用。

这里提供以下immutable类的五条规则:

  1. 不提供任何mutator
  2. 保证类不会被扩展
  3. 所有的域都是final的
  4. 所有的域都是私有的
  5. 确保对于任何可变组件的互斥性访问
    示例代码如下:
public class Position{
    private final int x;
    private final int y;
    private static Position ORIGIN = new Position(0,0);
    private Position(int x, int y){
        this.x = x;
        this.y = y;
    }

    public static Position getORIGIN(){
        return ORIGIN;
    }
    
    public int getX(){
        return x;
    }
    
    public int getY(){
        return y;
    }
}

静态工厂方法第三大优势:他们可以返回原返回类型的任何子类型的对象

这样我们在选择返回对象的类时就有了更大的灵活性。
这种灵活性的一种应用是,API可以返回对象,同时又不会使对象的类变成公有的。以这种方式隐藏实现类会使API变得非常简洁。这项技术适用于基于接口的框架(interface-basedframework),因为在这种框架中,接口为静态工厂方法提供了自然返回类型。接口不能有静态方法,因此按照惯例,接口Type的静态工厂方法被放在一个名为Types的不可实例化的类(见第4条)中。
示例代码如下:

public class Person {
    public static Person getStudent(){
        return new Student();
    }
}
class Student extends Person {

}//仅为一无内涵的示例

静态工厂方法的第四大优势在于,在创建参数化类型的实例的时候,他们使代码变得更加简介

此优势主要体现在泛型初始化时,示例代码如下:

    // 不使用静态工厂方法的情况:
    Map<String, Integer> map = new HashMap<String, Integer>();
    
    
    // HashMap中如果存在此方法:
    public Map<K,V> getInstance(){
        return new HashMap<K,V>();
    }
    
//    即可简化成以下代码
    Map<String, Integer> map = HashMap.getInstance();

静态方法的主要缺点是,类如果不含有共有的或受保护的构造器,就不能被子类化。

这一部分较有体会,例如以下代码(错误示例)

public class Person {
    private final SEX sex;
    private final String name;
    private final int age;

    private Person(String name, int age, SEX sex){
        this.sex = sex;
        this.name = name;
        this.age = age;
    }

    public static Person getManInstance(String name, int age){
        return new Person(name, age, SEX.man);
    }

    public static Person getWomanInstance(String name, int age){
        return new Person(name, age, SEX.woman);
    }
}

class Student extends Person {
    
}

实际在编译器的静态检查中会报错,原因是父类缺少公有的构造方法,而子类无法调用父类的私有构造器,导致子类无法生成构造器。

静态工厂方法的第二个缺点在于,他们与其他的静态方法实际没有任何区别

下面是一些静态工厂方法的惯用名称:

  1. valueOf——不太严格地讲,该方法返回的实例与它的参数具有相同的值。这样的静态工厂方法实际上是类型转换方法。
  2. of—— valueOf的一 种更为简洁的替代,在EnumSet (见第32条)中使用并流行起来。
  3. getInstance-返回的实例是通过方法的参数来描述的,但是不能够说与参数具有同样的值。 对于Singleton来说, 该方法没有参数,并返回唯一的实例。
  4. newInstance——像 getInstance-样, 但newInstance 能够确保返回的每个实例都与所有其他实例不同。
  5. getType——像getInstance- 样, 但是在工厂方法处于不同的类中的时候使用。Type表示工厂方法所返回的对象类型。
  6. newType——像newinstance一样,但是在工厂方法处于不同的类中的时候使用。Type表示工厂方法所返回的对象类型。

要不,点个赞?~

  • 46
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值