美文网首页
考虑用静态工厂方法代替构造器

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

作者: Luuuuuuffy | 来源:发表于2017-02-10 15:19 被阅读0次

静态工厂方法与构造器相比具有几大优势:

1. 有名称。比较清晰,且代码更易阅读。
例如:BigInteger.probablePrime(int, Random).

2. 不必在每次调用它们的时候都创建一个新对象。如果程序经常请求创建相同的对象,并且创建对象的代价很高,则可以极大地提升性能。可以为重复的调用返回相同的对象。这种类被称为实例受控的类,确保类为Singleton或者是不可实例化的,保证了不会存在两个相等的实例,可以用==操作符来代替equals(Object)方法,提升性能。(枚举类型保证了这一点)
例一:

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

例二:

public class Singleton {

    private static volatile Singleton singleton;

    private Singleton () { }

    public static Singleton getInstance() {
        if(singleton == null) {
            synchronized(Singleton.class) {
                if(singleton == null) {
                    singleton = new Singleton();
                } 
            }
        }
        return singleton;
    }

}

3. 可以返回原返回类型的任何子类型的对象。
例一:java.util.Collections提供了不可修改集合,同步集合等等便利实现。
例二:java.util.EnumSet没有公有的构造器,只有静态工厂方法。如果元素有64个或者更少,方法会返回一个RegalarEnumSet实例;如果元素有65个或者更多,方法就返回JumboEnumSet实例。
例三:服务提供者框架(Service Provider Framework),它有三个重要的组件:Service Interface 服务接口,Provider Registration API 提供者注册API,Service Access API 服务访问API。还有一个可选组件:Service Provider Interface 服务提供者接口,如果没有这个组件,实现就按类名称注册,并通过反射方式进行实例化。例如JDBC API,Connection就是服务接口,DriverManager.registerDriver是提供者注册API,DriverManager.getConnection是服务访问API,Driver就是服务提供者接口。

/**
 * Service Interface 服务接口:由提供者来实现
 * 音乐相关的基础服务
 */
public interface BaseMusicService {
    
    /**
     * 播放音乐服务
     */
    void playMusic();
    
    // TODO 更多其他服务...

}
/**
 * Service Provider Interface 服务提供者接口:由提供者负责创建其服务实现的实例
 * 基础音乐提供商
 */
public interface BaseMusicProvider {
    
    /**
     * 创建其服务实现的实例
     * @return
     */
    BaseMusicService newService();

}
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 应用市场
 * 可进行提供者的注册
 * 可获取服务的实例
 */
public class AppStore {
    
    // 该类不可实例化
    private AppStore() { }
    
    // 已注册的服务提供商
    private static final Map<String, BaseMusicProvider> providers = 
            new ConcurrentHashMap<String, BaseMusicProvider>();
    
    // 默认服务提供商的名称
    public static final String DEFAULT_PROVIDER_NAME = "Default";
    
    // Provider Registration API 提供者注册API:用来实现注册提供者
    public static void registerDefaultProvider(BaseMusicProvider p) {
        registerProvider(DEFAULT_PROVIDER_NAME, p);
    }
    
    public static void registerProvider(String name, BaseMusicProvider p) {
        providers.put(name, p);
    }
    
    // Service Access API 服务访问API:客户端用来获取服务实例的
    public static BaseMusicService newInstance() {
        return newInstance(DEFAULT_PROVIDER_NAME);
    }
    
    public static BaseMusicService newInstance(String name) {
        BaseMusicProvider p = providers.get(name);
        if(p == null){
            throw new IllegalArgumentException(
                    "No provider registered with name: " + name);
        }
        return p.newService();
    }

}
public class Test {

    public static void main(String[] args) {
        
        // 应用市场注册服务提供者
        AppStore.registerDefaultProvider(DEFAULT_PROVIDER);
        AppStore.registerProvider("QQ", QQ_PROVIDER);
        AppStore.registerProvider("NetEase", NETEASE_PROVIDER);
        
        // 用户获得不同的提供者提供的服务实例
        BaseMusicService s1 = AppStore.newInstance();
        BaseMusicService s2 = AppStore.newInstance("QQ");
        BaseMusicService s3 = AppStore.newInstance("NetEase");
        
        // 享受服务,播放音乐
        s1.playMusic();
        s2.playMusic();
        s3.playMusic();
        
    }
    
    private static BaseMusicProvider DEFAULT_PROVIDER = new BaseMusicProvider() {

        @Override
        public BaseMusicService newService() {
            return DEFAULT_PROVIDER_SERVICE;
        }
        
    };
    
    private static BaseMusicService DEFAULT_PROVIDER_SERVICE = new BaseMusicService() {

        @Override
        public void playMusic() {
            System.out.println("默认提供者开始播放音乐服务...");
        }
        
    };
    
    private static BaseMusicProvider QQ_PROVIDER = new BaseMusicProvider() {

        @Override
        public BaseMusicService newService() {
            return QQ_PROVIDER_SERVICE;
        }
        
    };
    
    private static BaseMusicService QQ_PROVIDER_SERVICE = new BaseMusicService() {

        @Override
        public void playMusic() {
            System.out.println("QQ音乐提供者开始播放音乐服务...");
        }
        
    };
    
    private static BaseMusicProvider NETEASE_PROVIDER = new BaseMusicProvider() {

        @Override
        public BaseMusicService newService() {
            return NETEASE_PROVIDER_SERVICE;
        }
        
    };
    
    private static BaseMusicService NETEASE_PROVIDER_SERVICE = new BaseMusicService() {

        @Override
        public void playMusic() {
            System.out.println("网易云音乐提供者开始播放音乐服务...");
        }
        
    };

}
----------------------------------------------------  
输出:
默认提供者开始播放音乐服务...
QQ音乐提供者开始播放音乐服务...
网易云音乐提供者开始播放音乐服务...

4. 创建参数化类型实例的时候,可以使代码变得更简洁。
例如:类型推导

Map<String, List<String>> m = new HashMap<String, List<String>>();

使用了静态工厂方法,可以用下面代替上面的繁琐的声明。

public static <K, V> HashMap<K, V> newInstance() {
    return new HashMap<K, V>();
}

Map<String, List<String>> m = HashMap.newInstance();

静态工厂方法的主要缺点在于:

1. 类如果不含公有的或受保护的构造器,就不能被子类化。类A extends 类B时,类B必须要有可用非私有的构造器。

2. 与其他静态方法实际上无区别。所以有以下惯用名称:

  • valueOf——类型转换。
  • of——valueOf更简洁的替代。
  • getInstance——通过方法的参数返回实例。
  • newInstance——同上,并能确保返回的每个实例都与其他实例不同。
  • getType——类似getInstance,在工厂方法中处于不同的类使用。
  • newType——类似newInstance,在工厂方法中处于不同的类使用。

相关文章

  • 创建和销毁对象

    1,考虑用静态工厂方法代替构造器 切忌第一反应就是提供共有构造器,而不先考虑静态工厂。 类可以通过静态工厂方法返回...

  • effective java读书笔记

    一、考虑用静态工厂方法代替构造器1.静态工厂方法有名称,而构造器只能是类名 private Map > map =...

  • effective java学习笔记 原则1:考虑用静态工厂方法

    原则1:考虑用静态工厂方法代替公有构造器 提供实例的方式:静态工厂方法(非设计模式中的静态工厂模式)公有构造器ne...

  • Java创建和销毁对象

    考虑用静态工厂方法代替构造器 静态工厂方法可以通过静态获取类的一个实例,而不需要通过构造器; 使用静态工厂方法的优...

  • java编程建议系列一

    1.考虑用静态工厂方法代替构造器 静态工厂方法惯用名称 valueOf —— 类型转换方法 of —— value...

  • 第一条 考虑用静态工厂方法代替构造器

    创建和销毁对象 考虑用静态工厂方法代替构造器 一般使用构造器 使用静态方法 这样写的优势 静态方法有名字构造器与类...

  • Effective Java--(1)创建和销毁对象

    1 考虑用静态工厂方法代替构造器 例如如下方法: 静态工厂方法和构造器都各有长处,我们需要理解各自长处,做出合适的...

  • 如何做到写出高效的Java代码?

    timg.jpeg 考虑用静态工厂方法代替构造器遇到多个构造器参数时要考虑用构建器用私有构造器或者枚举类型强化Si...

  • 第二章 创建和销毁对象

    1.考虑用静态工厂方法代替构造器 静态工厂方法与构造器不同的优势在于: 1.他们有名称(容易阅读) 2.不用每次调...

  • 2018-05-09

    1、用静态工厂方法代替构造器 2、遇到多个构造器参数时考虑用构建器 3、用私有构造器或者枚举类型强化Singlet...

网友评论

      本文标题:考虑用静态工厂方法代替构造器

      本文链接:https://www.haomeiwen.com/subject/jsdgittx.html