静态工厂模式

  

  静态工厂模式是一种改进的获取实例的方法。

  通常我们会使用new关键字调用类的构造方法来创建一个对象,静态工厂模式相对于传统的创建对象的方式有以下优点:

  1. 可以更加富有语义的创建实例当一个类的构造方法有非常多的参数或被重载过很多次的话,因为JAVA对构造方法命名的规定(与类名相同),我们必须编写多个命名相同但实际不同的构造函数,在创建对象时很难区分我们应该调用哪个构造方法。

  比如在实际生产中,我们会经常见到以下方法:

  newInstance():获取一个新的对象

  valueOf():获取一个值为..的对象

  getInstance():获取一个对象缓存池中的对象或单例对象

  甚至我们可以更加细分,比如有一个Person类,我们想根据年龄来获取不同的对象,则可有如下静态工厂方法:

  getChild():获取一个儿童对象

  getOld():获取一个老年对象

  getYouth():获取一个青年对象

  等等,比起new关键字,显然使用上述方法获取对象更加具有可读性,使我们对创造的实例类型更可控。

  2. 不必每次调用都创建新的对象

  当一个类的对象会被频繁使用,且没有必要在每次使用时都生成新的对象时,我们会考虑使用单例模式。单例模式大多是由静态工厂实现的,我们可以在工厂内部控制新生成实例或返回已有实例。

  比如,DCL单例模式获取对象时就是采用了静态工厂:

public class Car {
    //构造函数私有,禁止通过常规方式实例化
    private Car(){}
    //单例对象的引用
    static volatile Car car=null;
    //DCL获取单例对象,静态工厂方法
    static Car getInstance(){
        if(car==null){
            synchronized(Car.class){
                if(car==null){
                    car=new Car();
                }
            }
        }
        return car;
    }

    private Object readResolve() {
        return getCar();
    }
}

  3. 可以返回原返回类型的子类

  我们可以通过静态工厂返回一个类型的所有子类,可以更加灵活的获取实例。这也符合了两大设计原则:里氏替换原则依赖倒置原则。即所有父类可以出现的地方子类也可以出现,以及类的使用方不应该依赖具体的实现类,而应该依赖继承链的顶端(接口或抽象类),即依赖抽象。

  从Car中我们可以获取Bus和Taxi两个子类的实例,其它类在使用时只需维护一个Car的引用,至于具体用Bus还是用Taxi只由获取实例的那行代码决定,我们可以在只更换实例的获取而不改变其它代码(业务逻辑)的情况下修改代码。

public class Car{
    public static Car getBus(){
        return new Bus();
    }
    public static Car getTaxi(){
        return new Taxi();
    }

}

public class bus extends Car{

}

public class taxi extends Car{

}

  4. 在创建带泛型的参数时,使代码更简洁

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

  Map<String,Date> map = new HashMap<String,Date>();

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

  Map<String,Date> map = new HashMap<>();

  所以这个问题实际上已经不存在了。

  总的来说,静态工厂模式便是把创建实例的任务由使用方移到了提供方,基于提供方比使用方更了解自己的事实,这可以使对象的创建更加合理和可控。在实际生产时,我们应该优先考虑通过静态工厂模式获取实例。

posted @ 2019-11-26 16:21  牛有肉  阅读(1408)  评论(0编辑  收藏  举报