Fork me on GitHub

设计模式之工厂模式

设计模式之工厂模式

工厂模式分为以下三种:

  • 简单工厂模式

  • 工厂方法模式

  • 抽象工厂模式

1. 简单工厂模式

1.1 什么是简单工厂模式

简单工厂模式属于类的创建型模式,又叫做静态工厂方法模式。通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

  1. 工厂(Creator)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
  2. 抽象(Product)角色: 简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
  3. 具体产品(Concrete Product)角色:简单工厂模式所创建的具体实例对象

优缺点

优点:在这个模式中,工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优化。当需要大量的创建实例对象的时候使用工厂模式是可以的。
缺点:不难发现,简单工厂模式的缺点也正体现在其工厂类上,由于工厂类集中了所有实例的创建逻辑,所以“高内聚”方面做的并不好。另外,当系统中的具体产品类不断增多时,可能会出现要求工厂类也要做相应的修改,扩展性并不很好。

1.2 具体实例:

以一个披萨店为例,从下单到派送整个过程

首先需要一个Pizza的抽象类,现在是假设不同的披萨的烘焙,切割,装盒都是一样的,不同之处只是在原料。所以需要一个抽象类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class Pizza {
public String name;

public abstract void Prepare();

public void bake(){
System.out.println(name + ":"+ "bake");
}
public void cut(){
System.out.println(name + ":"+ "cut");
}
public void box(){
System.out.println(name + ":"+ "box");
}

public void setName(String name){
this.name = name;
}
}

不同的披萨去继承和扩展该类

1
2
3
4
5
6
7
public class CheesePizza extends Pizza {
@Override
public void Prepare() {
super.setName("CheesePizza");
System.out.println(name + "preparing" );
}
}

其余类型的同理。

然后下单

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
public class OrderPizza {
public OrderPizza() {
Pizza pizza = null;
String ordertype;

do {
ordertype = gettype();

if (ordertype.equals("cheese")) {
pizza = new CheesePizza();
} else if (ordertype.equals("greek")) {
pizza = new GreekPizza();
} else if (ordertype.equals("pepper")) {
pizza = new PepperPizza();
} else if (ordertype.equals("chinese")) {
pizza = new ChinesePizza();
} else {
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while (true);
}

private String gettype() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(
System.in));
System.out.println("input pizza type:");
String str = strin.readLine();

return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}

上面的那个类我们可以看出,每次添加新的披萨种类的时候我们需对这个类进行更新,不太符合对扩展开放,对修改封闭的开闭原则,所以我们需要用到工厂模式进行修改:

工厂模式:就是我们下单的时候需要很多的披萨的实例,要是直接就封装在下单的类中的话每次进行更改的话就需要不断地重现更改和加载那个类,所以就把实例有更改的地方抽取出来,单独作为一个类,就是所谓的工厂类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class SimplePizzaFactory {
public Pizza CreatePizza(String orderType){
Pizza pizza = null;
if (orderType.equals("cheese")) {
pizza = new CheesePizza();
} else if (orderType.equals("greek")) {
pizza = new GreekPizza();
}
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
}
return 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
27
28
29
30
31
32
public class OrderPizza {

public OrderPizza(SimplePizzaFactory simplePizzaFactory){
setSimplePizzaFactory(simplePizzaFactory);
}

public void setSimplePizzaFactory(SimplePizzaFactory simplePizzaFactory){
String orderType;
do {
orderType = getType();
Pizza pizza =simplePizzaFactory.CreatePizza(orderType);
if (pizza != null){
pizza.Prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
}while (true);
}

private String getType(){
try {
BufferedReader strIn = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type");
String str = strIn.readLine();
return str;
}catch (IOException e){
e.printStackTrace();
return "";
}
}
}
1
2
3
4
5
public class PizzaStore {
SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory();
OrderPizza orderPizza = new OrderPizza(simplePizzaFactory);

}

上面的例子就是简单工厂模式的一个下例子。

2. 工厂方法模式

2.1什么是工厂方法模式

工厂方法模式同样属于类的创建型模式又被称为多态工厂模式 。工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

  1. 抽象工厂(Creator)角色:工厂方法模式的核心,任何工厂类都必须实现这个接口。
  2. 具体工厂( Concrete Creator)角色:具体工厂类是抽象工厂的一个实现,负责实例化产品对象。
  3. 抽象(Product)角色:工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
  4. 具体产品(Concrete Product)角色 工厂方法模式所创建的具体实例对象

与简单工厂模式的比较:

  • 工厂方法模式与简单工厂模式在结构上的不同不是很明显。工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
  • 工厂方法模式之所以有一个别名叫多态性工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。
  • 当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭”原则。而简单工厂模式在添加新产品对象后不得不修改工厂方法,扩展性不好。
  • 工厂方法模式退化后可以演变成简单工厂模式。

2.2 具体实例

还是上面的例子,如果说我想要扩展了新的门店了,然后不同的门店是由不同的味道的,然后这个程序要扩展的话就需要修改工厂模式类,去new不同门店的实例,这样的话维护起来比较费劲,所以用工厂方法模式来进行改进,就是把工厂模式抽象成方法,具体如下:

首先就是订单类我们把该类做成抽象类,我们CreatePizza()这个方法单独拿出来变成抽象方法,由不同门店的类去扩展该类。

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
public abstract class  OrderPizza {
Pizza pizza = null;
public String orderType;

public OrderPizza(){
do {
orderType = getType();
pizza = CreatePizza(orderType);
if (pizza != null){
pizza.Prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
}while (true);
}

public abstract Pizza CreatePizza(String OrderType);

private String getType(){
try {
BufferedReader strIn = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type");
String str = strIn.readLine();
return str;
}catch (IOException e){
e.printStackTrace();
return "";
}
}
}

其中的一家店的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LDOrderPizza extends OrderPizza {

@Override
public Pizza CreatePizza(String OrderType) {
Pizza pizza = null;

if (orderType.equals("cheese")) {
pizza = new LDCheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new LDPepperPizza();
}
return pizza;
}
}

其余的所有的都是同理的,里面的一些披萨的具体的实例的初始化的类其实和上面是一样的,就不再赘述了。

1
2
3
4
5
public class PizzaStore {
public static void main(String[] args){
LDOrderPizza orderPizza = new LDOrderPizza();
}
}

3. 抽象工厂模式

3.1 什么是抽象工厂模式

抽象工厂模式是所有形态的工厂模式中最为抽象和最其一般性的。抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象。

  1. 抽象工厂(Creator)角色: 抽象工厂模式的核心,包含对多个产品结构的声明,任何工厂类都必须实现这个接口。
  2. 具体工厂( Concrete Creator)角色:具体工厂类是抽象工厂的一个实现,负责实例化某个产品族中的产品对象。
  3. 抽象(Product)角色: 抽象模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
  4. 具体产品(Concrete Product)角色:抽象模式所创建的具体实例对象
    总结:抽象工厂中方法对应产品结构,具体工厂对应产品族。

3.2 具体实例

其实抽象工厂模式就是定义了一个接口用于创建相关或有依赖关系的对象族,而无需明确指定具体类。也可以看做是把简单工厂模式抽象成了两级,抽象工厂的接口和具体的实现,形成工厂族。

还是上面的那个披萨店的例子,我们创建一个抽象工厂的接口,然后由不同的具体的工厂去继承该接口形成工厂族,然后在订单中去new抽象工厂就可以了,让他自己去选择下面是具体怎么实现的,具体的实现如下面所示:

抽象工厂接口:

1
2
3
4
public interface AbsFactory {
public Pizza CreatePizza(String ordertype) ;

}

不同具体的实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class NYFactory implements AbsFactory {
@Override
public Pizza CreatePizza(String ordertype) {
Pizza pizza = null;

if (ordertype.equals("cheese")) {
pizza = new NYCheesePizza();
} else if (ordertype.equals("pepper")) {
pizza = new NYPepperPizza();
}
return pizza;

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LDFactory implements AbsFactory{
@Override
public Pizza CreatePizza(String ordertype) {
Pizza pizza = null;

if (ordertype.equals("cheese")) {
pizza = new LDCheesePizza();
} else if (ordertype.equals("pepper")) {
pizza = new LDPepperPizza();
}
return 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
27
28
29
30
31
32
33
34
35
36
37
public class AbsOrderPizza {

AbsFactory absFactory;

public AbsOrderPizza(AbsFactory absFactory){
setAbsFactory(absFactory);

}

private void setAbsFactory(AbsFactory absFactory){
Pizza pizza = null;
String ordertype;

do {
ordertype = getOrderType();
this.absFactory = absFactory;
if (absFactory != null){
pizza = absFactory.CreatePizza(ordertype);
pizza.bake();
pizza.cut();
pizza.box();
}
}while (true);
}

private String getOrderType(){
try{
BufferedReader strIn = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type:");
String strs = strIn.readLine();
return strs;
}catch (IOException e){
e.printStackTrace();
return "";
}
}
}

在订单类中直接使用抽象工厂的接口就可以了,而不必去实现具体的什么工厂。

1
2
3
4
5
public class PizzaStore {
public static void main(String[] args){
AbsOrderPizza order = new AbsOrderPizza(new LDFactory());
}
}

总结

其实通过工厂模式我们可以看到一种设计规则就是依赖抽象原则,这也是设计模式的6大原则之一,依赖抽象原则的意义:

  • 变量不要持有具体类的引用

比方说我们这里面的我要去new 一个具体的工厂类,这这其实就是依赖性比较强了。

  • 不要让类继承自具体类,要继承自抽象类或接口,要是直接继承具体类的话依赖关系就很强了,不适合维护和扩展。
  • 不要覆盖基类中已经实现的方法。因为基类中的方法是通用方法,你要是有方法需要进行覆盖的话,这种方法是个性化的方法,你需要在具体类中去实现。

本文标题:设计模式之工厂模式

文章作者:WilsonSong

发布时间:2018年10月07日 - 15:10

最后更新:2018年10月07日 - 15:10

原始链接:https://songwell1024.github.io/2018/10/07/factory/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------本文结束感谢您的阅读-------------