工厂模式

什么是工厂模式

我们创建实例对象一般都是用new进行的,但是工厂模式将new的过程封装了起来,负责将大量实现了共同接口的类实例化。

工厂模式又分为

  1. 简单工厂模式:在具体工厂类里面创建抽象的产品。
  2. 工厂方法模式:在抽象工厂类里面创建抽象的产品。
  3. 抽象工厂模式:在抽象工厂类里面创建某个族的抽象的产品。

简单工厂模式

违背了开闭原则,不利于扩展

创建抽象产品IUser,以及两个具体产品MySQLUserSQLServerUser
通过SQLFactory工厂类创建具体产品。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/** 客户端  */
public class Main{
public static void main(String[] args){
IUser db = UserFactory.createUserDB(UserFactory.DB_MYSQL);
db.insertUser(new User());
}
}

/** 抽象的产品接口 */
public interface IUser {
void insertUser(User user);
}
/** 具体的产品 */
public class MySQLUser implements IUser{
public void insertUser(User user) {
System.out.println("MySQL插入一条用户数据");
}
}
public class SQLServerUser implements IUser{
public void insertUser(User user) {
System.out.println("SQLServer插入一条用户数据");
}
}

/** 简单工厂 */
public class SQLFactory {
public static final String DB_MYSQL="MySQL";
public static final String DB_SQLSERVER="SQLServer";
public static IUser createUserDB(String name){
IUser db = null;
switch(key){//通过key获取实例对象并返回
case DB_MYSQL:db = new MySQLUser();break;
case DB_SQLSERVER:db = new SQLServerUser();break;
}
return db;
}
}

如果需要新增子类,比如Oracle的用户类,那么就继承IUser类写一个子类,并在工厂中添加一个case分支。
但是缺点也在这里,每写一个子类,都要去修改已有的UserFactory工厂类,去新增case分支,这不符合开闭原则。

工厂方法模式

优化了简单工厂模式,但是大大增加了类的数量

创建抽象产品IUser,以及两个具体产品MySQLUserSQLServerUser
创建抽象工厂SQLFactory,以及两个具体工厂MySQLFactorySQLServerFactory
使用多态的特性,创建具体工厂,用来生产具体产品。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Main{ //客户端代码
public static void main(String[] args){
SQLfactory factory = new MySQLFactory();
IUser userDB = factory.createUserDB();
userDB.insertUser(new User());
}

/** 抽象的产品接口 */
public interface IUser {
void insertUser(User user);
}
/** 具体的产品 */
public class MySQLUser implements IUser{
public void insertUser(User user) {
System.out.println("MySQL插入一条用户数据");
}
}
public class SQLServerUser implements IUser{
public void insertUser(User user) {
System.out.println("SQLServer插入一条用户数据");
}
}

/** 抽象的工厂 */
public interface SQLFactory {//一个抽象工厂的接口
public IUser createUserDB();//创建工厂的工厂
}
/** 具体的工厂 */
public class MySQLFactory implements SQLFactory{
public IUser createUserDB() {
return new MySQLUser();
}
}
public class SQLServerFactory implements SQLFactory{
public IUser createUserDB() {
return new SQLServerUser();
}
}

在简单工厂模式的基础上,把工厂抽象出来,给每一个数据库添加一个工厂。
当需要添加新的数据库功能的时候,只要添加工厂或操作类即可。不用再去关注工厂中的判断分支(实际上已经没有判断分支了)。
缺点也在这,每添加一个子类功能的时候,都要创建两个类,工厂和操作类,增加了代码量。

抽象工厂模式

代码冗余,过度设计

创建抽象产品IUser,以及两个具体产品MySQLUserSQLServerUser
创建抽象产品IAuth,以及两个具体产品MySQLAuthSQLServerAuth
创建抽象工厂SQLFactory,以及两个具体工厂MySQLFactorySQLServerFactory
使用多态的特性,创建具体工厂,用来生产具体产品。
和工厂方法模式类似,只是增加了不同的产品。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class Main{ //客户端代码
public static void main(String[] args){
SQLfactory factory = new MySQLFactory();
IUser userDB = factory.createUserDB();
userDB.insertUser(new User());
IAuth authDB = factory.createAuthDB();
authDB.insertAuth(new Auth());
}
/** 抽象的产品接口 */
public interface IUser {
void insertUser(User user);
}
/** 具体的产品 */
public class MySQLUser implements IUser{
public void insertUser(User user) {
System.out.println("MySQL插入一条用户数据");
}
}
public class SQLServerUser implements IUser{
public void insertUser(User user) {
System.out.println("SQLServer插入一条用户数据");
}
}
/** 抽象的产品接口 */
public interface IAuth {
void insertAuth(Auth auth);
}
/** 具体的产品 */
public class MySQLAuth implements IAuth{
public void insertAuth(Auth auth) {
System.out.println("MySQL插入一条权限数据");
}
}
public class SQLServerAuth implements IAuth{
public void insertAuth(Auth auth) {
System.out.println("SQLServer插入一条权限数据");
}
}

/** 抽象的工厂 */
public interface SQLFactory {//一个抽象工厂的接口
public IUser createUserDB();//创建工厂的工厂
public IAuth createAuthDB();//创建工厂的工厂
}
/** 具体的工厂 */
public class MySQLFactory implements SQLFactory{
public IUser createUserDB() { return new MySQLUser(); }
public IAuth createAuthDB() { return new MySQLAuth(); }
}
public class SQLServerFactory implements SQLFactory{
public IUser createUserDB() { return new SQLServerUser(); }
public IAuth createAuthDB() { return new SQLServerAuth(); }
}

用简单工厂+反射+配置文件优化抽象工厂

删除SQLFactoryMySQLFactorySQLServerFactory三个工厂。
融合成一个SQLFactory类,再通过properties配置文件加载类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
public class Main{ //客户端代码
public static void main(String[] args){
IUser userDB = SQLFactory.createUserDB();
userDB.insertUser(new User());
IAuth authDB = SQLFactory.createAuthDB();
authDB.insertAuth(new Auth());
}
/** 抽象的产品接口 */
public interface IUser {
void insertUser(User user);
}
/** 具体的产品 */
public class MySQLUser implements IUser{
public void insertUser(User user) {
System.out.println("MySQL插入一条用户数据");
}
}
public class SQLServerUser implements IUser{
public void insertUser(User user) {
System.out.println("SQLServer插入一条用户数据");
}
}
/** 抽象的产品接口 */
public interface IAuth {
void insertAuth(Auth auth);
}
/** 具体的产品 */
public class MySQLAuth implements IAuth{
public void insertAuth(Auth auth) {
System.out.println("MySQL插入一条权限数据");
}
}
public class SQLServerAuth implements IAuth{
public void insertAuth(Auth auth) {
System.out.println("SQLServer插入一条权限数据");
}
}

/** 抽象的工厂 */
public class SQLFactory {
private static String dbName;
/** 从db.properties中获取数据库信息 */
static {
try(InputStream in = SQLFactory.class.getResourceAsStream("/db.properties");) {
Properties prop = new Properties();
prop.load(in);
for (Object key : prop.keySet()) {
if(key.equals("dbName")){
dbName = prop.getProperty((String) key);
}
}
} catch (IOException e) {
e.printStackTrace();
}

}

/** 通过反射获取IUser产品 */
public static IUser createUserDB(){
try {
Class clazz = Class.forName(dbName+"User");
return (IUser) clazz.getConstructor().newInstance();;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/** 通过反射获取IAuth产品 */
public static IAuth createAuthDB(){
try {
Class clazz = Class.forName(dbName+"Auth");
return (IAuth) clazz.getConstructor().newInstance();;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}