定义:
由一个工厂对象决定创建出哪一种产品类的实例.
类型:
创建型(creational), 但不属于GOF23种设计模式.
适用场景:
1, 负责创建的对象比较少.
2, 应用层只知道传入工厂类的参数,对于如何创建对象并不关心.
优点:
实现简单
工厂模式实例:
创建一个生产获取数据库连接的工厂
先抽象出产品接口
public interface DBConnection {
String getConnection();
}
实现获取Mysql和Oracle连接:
public class MysqlConnection implements DBConnection{
@Override
public String getConnection() {
return "Mysql Connection";
}
}
public class OracleConnection implements DBConnection{
@Override
public String getConnection() {
return "Oracle Connection";
}
}
简单工厂模式实现连接工厂:
public class DBConnectionFactory {
public DBConnection getConnection(String name){
if("mysql".equalsIgnoreCase(name)){
return new MysqlConnection();
}else if("oracle".equalsIgnoreCase(name)){
return new OracleConnection();
}else {
throw new IllegalArgumentException("no such connection");
}
}
}
测试:
public class Test1 {
public static void main(String[] args) {
DBConnectionFactory factory = new DBConnectionFactory();
DBConnection connection = factory.getConnection("mysql");
System.out.println(connection.getConnection());
// TODO sth
}
}
客户端只需传入需要的数据库名称即可获取到想要的数据库连接而无需关心工厂类实现细节, 如果客户端需要更改数据库连接, 只需要修改mysql为oracle即可,非常方便.
DBConnectionFactory 中的 getConnection 方法可以用静态方法实现,这样客户端就无需创建一个工厂对象出来.
但是这种方式也有缺点, 如果我需要新增一个数据库如sql server, 那么久必须修改getConnection 方法, 这明显违背了开闭原则.
使用反射解决上述问题.
public class DBConnectionFactory2 {
public static <T extends DBConnection> DBConnection getConnection(Class<T> clazz){
try {
return (DBConnection) Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
使用方法
public class Test2 {
public static void main(String[] args) {
DBConnection connection = DBConnectionFactory2.getConnection(MysqlConnection.class);
System.out.println(connection.getConnection());
// TODO sth
}
}
这样就避免了新增实现类之后需要修改工厂类的尴尬.
JDK中的单例模式:
如 java.util.Calendar#createCalendar
其中
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
根据参数的不同返回不同的实现
网友评论