简单工厂模式

需求引入

一个披萨的项目:要便于披萨种类的扩展,要便于维护

  • 披萨的种类很多(PepperPizza、CheesePizza、PizzaStore)
  • 披萨的制作流程(prepare、bake、cut、box)
  • 完成披萨店订购功能

使用传统方式

思路

image-20190824151203394

代码

Pizza

1
2
3
4
5
6
public abstract class Pizza {
public abstract void prepare();
public abstract void bake();
public abstract void cut();
public abstract void box();
}

PepperPizza

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class PepperPizza extends Pizza{

private String name;

@Override
public void prepare() {

}

@Override
public void bake() {

}

@Override
public void cut() {

}

@Override
public void box() {

}
}

CheesePizza

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class CheesePizza extends Pizza{

private String name;

@Override
public void prepare() {

}

@Override
public void bake() {

}

@Override
public void cut() {

}

@Override
public void box() {

}
}

VeggiePizza

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class VeggiePizza extends Pizza{

private String name;

@Override
public void prepare() {

}

@Override
public void bake() {

}

@Override
public void cut() {

}

@Override
public void box() {

}
}

PizzaStore

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
public class PizzaStore {

public Pizza orderPizza(String orderType){
Pizza pizza = null;
if (orderType.equals("veggie")) {
pizza = new VeggiePizza();
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
}
// 而当披萨店增加或者删除披萨类型时,必须修改 PizzaStore 的代码。例如想要添加一个“中国披萨”,那么就要添加:
/*else if (orderType.equals("china")) {
pizza = new ChinaPizza();
}*/
/**
* 明显违反了“开放-关闭原则”,并没有做到对修改“关闭”。
* 如何优化呢?这里得引出“简单工厂模式”了。
*/
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}

优缺点

  • 优点比较好理解,简单易操作
  • 缺点是违反了设计模式的ocp原则,即对扩展开放,对关闭修改。即当我们给类增加新功能的时候,尽量不要修改代码,或尽可能少修改代码。

改进思路

分析:修改代码可以接受,但是如果我们在其他的地方也有创建Pizza的代码,就意味着,也需要修改,而创建Pizza的代码,往往有多出。

思路:把创建Pizza对象封到一个类中,这样我们就有新的Pizza种类时候,只需要修改该类就可以,其他有创建到Pizza对象的代码就不需要修改了。—— 简单工厂模式

基本介绍

  • 简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,属于创建型模式,是工厂模式的一种。
  • 简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。直白地讲,简单工厂把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化,这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类。
  • 简单工厂模式并不在 GoF 23 种设计模式之列,与其说其是设计模式,不如说是一种编程习惯。
  • 简单工厂模式中包含如下要素:
    • Factory:工厂,工厂负责实现创建所有实例的内部逻辑。
    • Product:抽象产品,抽象产品是所创建的所有对象的父类,负责描述所有实例所共有的公共接口。
    • ConcreteProduct:具体产品, 具体产品是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

使用简单工厂模式

思路

  • 定义一个可以实例化Pizza对象的类,封装创建对象的代码。

image-20190824153233184

代码

SimpleFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
public class SimpleFactory {
public static Pizza createPizza(String orderType){
Pizza pizza = null;
if (orderType.equals("veggie")) {
pizza = new VeggiePizza();
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
}
return pizza;
}
}

OrderPizza

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
public class OrderPizza {

private SimpleFactory simpleFactory;

public OrderPizza(SimpleFactory simpleFactory) {
this.simpleFactory = simpleFactory;
}

public SimpleFactory getSimpleFactory() {
return simpleFactory;
}

public void setSimpleFactory(SimpleFactory simpleFactory) {
this.simpleFactory = simpleFactory;
}

public Pizza orderPizza(String orderType){
Pizza pizza = simpleFactory.createPizza(orderType);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}

优缺点

  • 优点
    • 工厂类含有必要的判断逻辑,可决定创建产品类的实例的实际时刻。工厂和产品的职责区分明确,客户端仅仅“消费”产品。
    • 客户端(PizzaStore)只需要知道具体产品类所对应的参数即可。
    • 通过引入配置文件,可在不修改任何客户端代码的情况下更换和增加新的具体产品类,提高了系统的灵活性。
  • 缺点
    • 工厂类集中了所有产品创建逻辑,职责过重,一旦发生异常,整个系统将受影响。
    • 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
    • 系统扩展困难一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
    • 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

工厂方法模式

需求引入

披萨项目新需求:客户在点披萨时候,可以点不同口味的披萨,比如:北京的奶酪Pizza,北京的胡椒Pizza,或者上海的奶酪Pizza,上海的胡椒Pizza

思路1

使用简单工厂模式,创建不同的简单工厂类,比如:BJPizzaSimpleFactory,SHPizzaSimpleFactory 等等。从当前案例来说也是可以,当考虑到项目的规模,以及软件的可维护性,可扩展性并不是很好。

思路2

使用工厂方法模式

基本介绍

  • 工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。
  • 在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
  • 直白地讲,“工厂方法模式”是对简单工厂模式的进一步抽象化,只是工厂方法把产品的实例化操作推迟到子类。
  • 工厂方法模式中包含如下要素:
    • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 createProduct() 来创建产品。
    • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
    • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
    • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

20190824012551846

使用工厂方法模式

思路

  • 将披萨项目的实例化功能抽象方法,在不同的口味餐子类中具体实现。
  • 那么就可以把createPizza(orderType)放回OrderPizza中,不过设置为“抽象方法”,然后每个区域设置自己的OrderPizza子类。

image-20190824160037765

代码

OrderPizza

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class OrderPizza {

abstract Pizza createPizza(String orderType);

public Pizza orderPizza(String orderType) {
Pizza pizza;

pizza = createPizza(orderType);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}

}

BeijingOrderPizza

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BeijingOrderPizza extends OrderPizza {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("veggie")) {
pizza = new VeggiePizza();
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
}
return pizza;
}
}

ShanghaiOrderPizza

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ShanghaiOrderPizza extends OrderPizza {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("veggie")) {
pizza = new VeggiePizza();
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
}
return pizza;
}
}

优缺点

  • 优点
    • 用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
    • 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
    • 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
  • 缺点
    • 类的个数容易过多,增加复杂度。
    • 考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度。
    • 抽象产品只能生产一种产品。

抽象工厂

问题引入

为了更清晰地理解工厂方法模式,先理解两个概念:

  • 产品等级 :产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
  • 产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。

4087bdfd1e8aa158cad3eaae55c9687d

基本介绍

  • 象工厂模式(Abstract Factory Pattern):定义一个interface接口,用于创建一系列相关或相互依赖对象的家族,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。
  • 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
  • 从设计层面看,抽象工厂模式是对简单工厂模式的改进(或者称为进一步抽象)。
  • 抽象工厂模式与工厂方法模式区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。
  • 抽象工厂模式同工厂方法模式一样,也是由4 个要素构成,但抽象工厂中方法个数不同,抽象产品的个数也不同
    • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 createProduct() 来创建产品。
    • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
    • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
    • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

20190824102427204

使用抽象工厂模式

思路

image-20190824164640686

代码

AbsFactory

1
2
3
public interface AbsFactory {
public Pizza createPizza(String orderType);
}

BeijingFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BeijingFactory implements  AbsFactory{
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("veggie")) {
pizza = new VeggiePizza();
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
}
return pizza;
}
}

ShanghaiFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ShanghaiFactory implements AbsFactory{
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("veggie")) {
pizza = new VeggiePizza();
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
}
return pizza;
}
}

OrderPizza

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class OrderPizza {
private AbsFactory absFactory;

public OrderPizza() {
}

public OrderPizza(AbsFactory absFactory) {
this.absFactory = absFactory;
}

public Pizza orderPizza(String orderType){
Pizza pizza = absFactory.createPizza(orderType);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}

优缺点

  • 优点
    • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建,从具体的产品解耦出来。
    • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
    • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
  • 缺点
    • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)

抽象工厂模式案例(多个产品)

AbstractProductX

1
2
public class AbstractProductX {
}

AbstractProductY

1
2
public class AbstractProductY {
}

ConcreteProductAX

1
2
public class ConcreteProductAX extends AbstractProductX {
}

ConcreteProductBX

1
2
public class ConcreteProductAX extends AbstractProductX {
}

ConcreteProductAY

1
2
public class ConcreteProductAY extends AbstractProductY {
}

ConcreteProductBY

1
2
public class ConcreteProductBY extends AbstractProductY {
}

AbstractFactory

1
2
3
4
public abstract class AbstractFactory {
abstract AbstractProductX createProductX();
abstract AbstractProductY createProductY();
}

ConcreteFactoryA

1
2
3
4
5
6
7
8
9
public class ConcreteFactoryA extends AbstractFactory {
AbstractProductX createProductX() {
return new ProductAX();
}

AbstractProductY createProductY() {
return new ProductAY();
}
}

ConcreteFactoryB

1
2
3
4
5
6
7
8
9
public class ConcreteFactoryB extends AbstractFactory {
AbstractProductX createProductX() {
return new ProductBX();
}

AbstractProductY createProductY() {
return new ProductBY();
}
}

Client

1
2
3
4
5
6
7
8
public class Client {
public static void main(String[] args) {
AbstractFactory abstractFactory = new ConcreteFactoryA();
AbstractProductX productX = abstractFactory.createProductX();
AbstractProductY productY = abstractFactory.createProductY();
// do something with productX and productY
}
}