在介绍了工厂方法模式之后,介绍这一博客内容。
参数化工厂/静态工厂中的分支语句,不遵循OCP,因此例程3-7显得难看(但是简洁。俗话说得好,一个简洁三个爱。)。而工厂方法模式又不愿意作为Client→IServer的使能工具。可以采用工厂方法模式对静态工厂加以改进。
package chap3.init;
import commons.*; //IServer类层次
public class ServerFactory{
public static IServer create(String typeName) {//int ID
if(typeName.equals("S1")){
return new S1();
}else if(typeName.equals("S2")){
return new S2();
}else{
return null;
}
}
}
首先采用Java之enum技术,以一个类IServerType封装例程3-10中工厂方法模式结构推导时采用的IServerFactory的类层次。IServerType与IServerFactory一样定义了工厂方法create();IServer有子类型S1和S2时,IServerFactory也必须对应地有两个子类型,而IServerType通过匿名类定义它们。当然,IServerType一个人就封装了人家的类层次,如果IServer添加子类型S3,则工厂方法模式中只需要增加S3Factory而不必修改其他代码,IServerType则不得不修改源代码以添加新的枚举项(本质上和分支语句一样)。
package chap3.factory;
import commons.*;//IServer类层次
/**
* 采用Java的enum技术,以一个类IServerType封装例程3-10中IServerFactory的类层次
*
* @author (your name here)
* @version (version number or date here)
*/
enum IServerType{
S1("S1"){ //匿名类
@Override public IServer create(){
return new S1();
}
},
S2("S2"){
@Override public IServer create(){
return new S2();
}
};
private String type;
private IServerType( String type ) {
this.type = type;
}
public abstract IServer create();
}
然后,ServerFactory不需要明显难看的分支语句。注意IServerType并非public,因此被隐藏在ServerFactory的背后,呈现给用户的仍然是一个参数化工厂。如果将IServerType设计为public,则不需要ServerFactory这个类,外界可以直接使用IServerType。
package chap3.factory;
import java.util.HashMap;
public class ServerFactory{
private static HashMap<String,IServerType> typeMap = new HashMap<>();
static{
typeMap.put("S1", IServerType.S1);
typeMap.put("S2", IServerType.S2);
}
public static commons.IServer getObject(String typeName){
return typeMap.get(typeName).create();
}
}
//外界使用
public static void test(){
IServer s = ServerFactory.getObject("S1");
s.doSth();
s = IServerType.valueOf("S2").create();
s.doSth();
本实现中采用了工厂方法模式,避免了静态工厂的分支结构,而且没有了工厂方法模式中显式出现的工厂类层次,即使直接使用IServerType也不会难受。但是,本实现与静态工厂一样,在IServer添加子类型S3时需要修改源代码。
作业:讨论参数化工厂,工厂方法模式的优缺点。工厂模式的enum实现的优缺点。
链接:Java之enum