工厂模式有三种分类,其中包括简单工厂模式、工厂方法模式以及抽象工厂模式。
1. 简单工厂模式
又称为静态工厂方法(Static Factory Method)模式, 简单工厂模式专门定义一个类来负责创建其他类的实例,代码中可以根据参数的不同返回不同类的实例, 并且被创建的实例通常都具有共同的父类。但是简单工厂模式其实不是一个设计模式,反而比较像是一种编程习惯。
这里将使用 简单工厂模式 的模式分析。
- 简单工厂模式最大的问题在于工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,这一点与开闭原则是相违背的。
- 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。
个人认为只有懂得该模式的应用场景,明白其存在的意义,才能更好的理解和践行。
应用场景:
- JDK类库中广泛使用了简单工厂模式,如工具类java.text.DateFormat,它用于格式化一个本地日期或者时间。
public final static DateFormat getDateInstance(int style,Locale locale); - Java加密技术 (获取不同加密算法的密钥生成器)
KeyGenerator keyGen=KeyGenerator.getInstance("DESede");
对于《Head First Design Pattern》一书来说,简单工厂模式就是当需要不同类型的披萨时, 传入PizzaFactory不同的参数(”cheese”、”clam”、”veggies”)等来获取。 但是这种方式在加入新的类型的披萨的时候,就需要改动工厂类的判断逻辑。
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
class PizzaFactory {
public Pizza createPizza(String type) {
if (type.equals("cheese"))
return new CheesePizza();
else if (type.equals("clam"))
return new ClamPizza();
return null;
}
}
abstract class Pizza {
protected String name;
public abstract void eat();
}
class ClamPizza extends Pizza {
public ClamPizza() { name = "clam pizza"; }
public void eat() { System.out.println("Eating " + name); }
}
class CheesePizza extends Pizza {
public CheesePizza() { name = "cheese pizza"; }
public void eat() { System.out.println("Eating " + name); }
}
public class Client {
public static void main(String []args) {
PizzaFactory factory = new PizzaFactory();
Pizza pizza = factory.createPizza("clam");
pizza.eat();
}
}
上述代码你可以看出当你需要添加veggies或者pepperoni类型的披萨时,你需要改变PizzaFactory中的代码。 这一点将在工厂方法模式中进行修改。
2. 工厂方法模式
工厂方法模式(Factory Method Pattern)又称为工厂模式, 也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式, 它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口, 而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成, 即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
通过上述披萨的例子来理解就是,由于简单工厂模式的变动会导致修改代码中的逻辑判断,
通过工厂模式进行修改,就是将PizzaFactory设置为接口并定义其必须实现的方法,创建CheesePizzaFactory、
ClamPizzaFactory等实现该接口,必要时就通过该子工厂类来创建不同类型的pizza。
使用该方法来进行改进后,当你需要添加新类型pizza的时候,你只需要添加相应的产品和工厂即可,
而不需要去改动工厂中的逻辑代码。
应用场景
- JDBC中的工厂方法
1
2
3
4
5
6
7
class Template{
public void connect() {
Connection conn=DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=DB;user=sa;password=");
Statement statement=conn.createStatement();
ResultSet rs=statement.executeQuery("select * from UserInfo");
}
}
下面通过改写pizza的例子来更好的理解:
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
interface PizzaFactory {
Pizza createPizza();
}
class CheesePizzaFactory implements PizzaFactory {
public Pizza createPizza() { return new CheesePizza(); }
}
abstract class Pizza {
protected String name;
public abstract void eat();
}
class CheesePizza extends Pizza {
public CheesePizza() { name = "cheese pizza"; }
public void eat() { System.out.println("Eating " + name); }
}
public class Client {
public static void main(String []args) {
PizzaFactory factory = new CheesePizzaFactory();
Pizza pizza = factory.createPizza();
pizza.eat();
}
}
但是工厂模式会有相应的缺点,即会使系统中类的个数将成对增加,在一定程度上增加了系统的复杂度, 有更多的类需要编译和运行,会给系统带来一些额外的开销。
3. 抽象工厂模式
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。
抽象工厂模式的定义非常抽象,但是通过pizza的例子可以很好的理解其中的意思。
由于不同地区的披萨都有不同的配料,比如像chicago的奶酪披萨和new york的奶酪披萨就一定的区别。 这时候抽象工厂模式就排上用场了。将配料也设计成工厂的形式,并且不同的地区有不同的工厂类。 将需要的配料工厂注入进披萨工厂中,使其通过”组合”来完成(工厂方法模式是使用”继承”)。
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
interface PizzaFactory {
Pizza createPizza(PizzaIngredient ingredient);
}
class CheesePizzaFactory implements PizzaFactory {
public Pizza createPizza(PizzaIngredient ingredient) { return new CheesePizza(ingredient); }
}
abstract class Pizza {
protected String name;
public abstract void eat();
}
class CheesePizza extends Pizza {
private PizzaIngredient ingredient;
public CheesePizza(PizzaIngredient ingredient) {
name = "cheese pizza";
this.ingredient = ingredient;
}
public void eat() {
String result = name + " with ";
for (String ingre: ingredient.createIngredient())
result += ingre + ", ";
System.out.println("Eating " + result);
}
}
interface PizzaIngredient { // 将pizza配料设计成工厂接口的形式
ArrayList<String> createIngredient();
}
class NYPizzaIngredient implements PizzaIngredient{ // 不同的地区有不同的配料
public ArrayList<String> createIngredient() {
ArrayList<String> ingredient = new ArrayList<>();
ingredient.add("double cheese");
ingredient.add("milk");
return ingredient;
}
}
public class Client {
public static void main(String []args) {
PizzaFactory factory = new CheesePizzaFactory();
// 将配料工厂注入进做pizza的工厂中
Pizza pizza = factory.createPizza(new NYPizzaIngredient());
pizza.eat();
}
}