在正文介绍之前,首先要推荐一本书《Effective Java》,不瞒读者说这本书也是我的经理推荐给我的。刚拿到这本书时仅仅将近300页,还是比较精简的。但翻开第一章就给我的触动很大,有一些我们开发当观众经常用到的开发模式和写法,其实我们使用过程中并不在意,就拿静态工厂和构造器两种用法来说,本书就讲的非常细致,一定要第一时间把它看完,这本书可谓是非常经典的书籍。
1.静态工厂方法
以Java中自带的Boolean类为例,他的静态工厂方法为:
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
值得考虑的是该方法替代了构造器获得了一个Boolean的实例。
//使用构造器的模式
Boolean b1 = new Boolean(true);
//使用静态方法模式
Boolean b2 = Boolean.valueOf(true);
可以发现两种形式都是传入true参数,那它们的区别在哪呢?
1.1静态工厂方法优点
这就不得不说一下静态方法的优点了,从个人的角度来看我理解到有如下几个优点:
1)它们都有自己的名称,可实现自定义最大化
比如现在需要提供多个具有相同签名的构造器,这显然是Java不能实现的,除非将参数的列表顺序做个调整,这显然不够优雅。这时静态工厂方法就派上用场,可以自定义针对性较强的名字来表示不同的构造方式,从而提升了代码的可读性。
2)不需要每次调用时候都创建新的实例。
例如经典的单例模式就诠释了这一点。
3)整体的提升可读性,对代码结构也优化了许多。
就拿泛型类实例来比较:
//使用构造器创建
Map<String, List<String>> m1 = new HashMap<String, List<String>>();
//使用静态工厂方法创建
Map<String, List<String>> m2 = newInstance();
前提是提供了静态方法工厂newInstance方法:
public static <K, V> HashMap<K, V> newInstance() {
return new HashMap<K, V>();
}
1.2举一个生活中的例子:
- 服务接口:应用市场的游戏客户端
- 服务提供者接口:应用市场的商家
- 提供者注册API:王者荣耀APP向应用市场注册
- 服务访问API:用户下载游戏客户端
interface GameApp {
void play();
}
interface GameProvider {
GameApp getGameApp();
}
public class AppStore {
private AppStore() {}
private static final Map<String, GameProvider> provider = new ConcurrentHashMap<String, GameProvider>();
//服务注册API
public static void registerProvider(String name, GameProvider p) {
provider.put(name, p);
}
//服务访问API
public static GameApp installApp(String name) {
GameProvider p = provider.get(name);
if (p == null) {
throw new IllegalArgumentException("No provider registerd with name:" + name);
}
return p.getGameApp();
}
}
在这里我定义了服务注册的APIregisterProvider负责给游戏提供商注册到应用市场里。随后用户可以通过服务访问APIinstallApp来下载安装指定的App到设备上。
服务提供商可根据需要来实现服务接口和服务接口提供者接口,如:
class KingAppAndroid implements GameApp {
@Override
public void play() {
System.out.println("欢迎来到王者荣耀~Android客户端");
}
}
class KingAppIos implements GameApp {
@Override
public void play() {
System.out.println("欢迎来到王者荣耀~ios客户端");
}
}
class KingGameProvider implements GameProvider {
@Override
public GameApp getGameApp() {
//真实情况可根据访问渠道来判断
boolean isFromAndroid = true;
if (isFromAndroid) {
return new KingAppAndroid();
}
return new KingAppIos();
}
}
在这里我实现了两个常用的移动服务端类型。后面可根据用户的访问渠道进行对应的实现。如下:
public static void main(String[] args) {
AppStore.registerProvider("KingGame", new KingGameProvider());
GameApp app = AppStore.installApp("KingGame");
app.play();
}
实现流程是首先把服务提供者的应用注册到应用市场。用户只需要根据商家定义的名字就可以找到对应的App客户端实例,不需要指定与客户端实例相关的任何操作,从而实现了用户与服务的解耦。在本例中我只为移动端的两种渠道做了实例,而在真实的开发需求中,由于机型的适配、以及版本的不同会有更多的实例配置,但具体给用户创建哪个实例都是由服务提供者根据真实需求配置决定的,用户不需要操心这些。