您的位置:首页 > Web前端

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

2017-09-06 23:34 686 查看

构造器与静态工厂方法对比

Boolean对象中的静态工厂方法

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


下面两种对象生成方式比较

//使用构造器
Boolean b1 = new Boolean(true);
//使用静态工厂方法
Boolean b2 = Boolean.valueOf(true);


传入同样的参数为什么要用静态工厂方法替代构造器呢?

静态工厂方法优点

第一:静态工厂方法有名称

一个类只能有一个带有指定签名(JVM为我们提供的方法签名实际上是由方法名、形参列表、返回值三部分构成的)的构造器。而静态工厂方法我们可以通过不同的名称来描述不同的构造方法,便于代码阅读。

第二:不必每次调用时都创建一个新的对象

Boolean.valueOf(boolean)方法就说明了这个有点,使用预先构建好的实例,或者将构建好的实例缓存起来,进行重复利用。

第三:可以返回原返回类型的任何子类型的对象

静态工厂方法返回对象所属的类可以是后来动态添加的。具体可以看后面的服务提供者框架

第四:在创建参数化类型实例时更简洁

假如HashMap提供了这个静态工厂

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


那么

//使用构造器创建
Map<String, List<String>> m1 = new HashMap<String, List<String>>();
//使用静态工厂方法创建
Map<String, List<String>> m2 = HashMap.newInstance();


服务提供者框架

服务提供者框架是指:多个服务提供者实现一个服务,系统为客户端提供多个实现,并把他们从多个实现中解耦出来。静态工厂方法返回的对象所属的类,在编写包含该静态工厂方法的类时可以不必存在。这种灵活的静态工厂方法构成 服务提供者框架 的基础。典型应用JDBC API。

服务提供者三个重要组件:

服务接口

提供者注册API

服务访问API

服务提供者接口(可选)

首先我们先来看一下jdbc中获取mysql数据库连接对象的源码:

Class.forName("com.mysql.jdbc.Driver");
DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123");


以北京地铁进出控制为例:现在北京地铁进出都是刷卡,有二种卡:1.一卡通(比如一次性冲值50元,进地铁刷一次,出地铁刷一次,扣2元)。2.一次性卡(进地铁刷一次,出地铁插入回收。)



服务定义接口

//进出地铁服务接口
public interface SubWayInterface {

//进入地铁
public boolean in();

//出地铁
public boolean out();

}


服务具体实现

//一卡通地铁进出服务实现
public class SubWayImpl implements SubWayInterface {

public boolean in() {
System.out.println("通过一卡通进入地铁");
/**
* 进行一些处理,然后返回是否放行
*/
return false;
}

public boolean out() {
System.out.println("通过一卡通出地铁");
/**
* 进行一些处理,然后返回是否放行
*/
return false;
}

}


服务提供者接口

//地铁进出服务提供者接口
public interface SubwayProviderInterface {

public SubWayInterface getService();

}


服务提供者具体实现

//服务提供者实现类 这里返回了服务接口SubWayInterface
public class SubwayProviderImpl implements SubwayProviderInterface {

static {
ServiceManager.registerProvider("一卡通", new SubwayProviderImpl());
}

public SubWayInterface getService() {
return new SubWayImpl();
}

}


服务提供者注册类实现

public class ServiceManager {

private ServiceManager() {

}

private static final Map<String, SubwayProviderInterface> providers = new ConcurrentHashMap<String, SubwayProviderInterface>();

public static void registerProvider(String name, SubwayProviderInterface p) {
providers.put(name, p);
}

public static SubWayInterface getService(String name) {

SubwayProviderInterface p = providers.get(name);

if (p == null) {
throw new IllegalArgumentException(
"No provider registered with name:" + name);
}

return p.getService();

}

}


测试

public static void main(String[] args) throws ClassNotFoundException {
//Class.forName("")里面的参数放的完整包路径加类名                Class.forName("cn.netjava.cgl.subway.SubwayProviderImpl");
SubWayInterface swi = ServiceManager.getService("一卡通");
swi.in();
swi.out();
}


缺点

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

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

惯用名称

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

of-valueOf的一种简洁替代。

getInstance-返回的实例是通过方法的参数来描述的,但是对于Singleton来说,该方法没有参数,并返回唯一的实例。

newInstance-可以确保返回的每个实例都不同

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

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

参考

JAVA服务提供者框架介绍 作者:liwenshui322
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息