设计模式4-Factory

本文最后更新于:3 years ago

工厂模式

  工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于 创建型模式 ,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

如果想了解工厂模式的具体的介绍,菜鸟教程介绍得比较详细↓
菜鸟教程-工厂模式

结构图




优缺点

优点:
1、一个调用者想创建一个对象,只要知道其名称就可以了。
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点: 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

使用场景

1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
3、设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。

实现代码

简单工厂

首先实现需求,任意定制交通工具,然后实现Moveable()接口

这里我们首先创建三个对象,Car、Plane、Broom,实现Moveable接口

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
Moveable
public interface Moveable {
void go();
}

Car
public class Car implements Moveable{
@Override
public void go() {
System.out.println("Car go");
}
}

Plane
public class Plane implements Moveable{
@Override
public void go() {
System.out.println("Plane go");
}
}

Broom
public class Broom implements Moveable{
@Override
public void go() {
System.out.println("Broom go");
}
}

Main
public static void main(String[] args)
{
Moveable m = new Car();
m.go();
}

在任意定制交通工具之后,这时我要求任意定制生产过程
什么意思呢?比如说,当我们生产交通工具时,我们要求控制其权限
有人会说,我在new 之前写一串判断的代码,但仔细想想,我们不止单单Car一个类,
对于Car、Broom、Plane等等,它的权限是不一样的
这就意味着,如果你在new之前写了判断,则创建不同的类型实例,就要更改代码

解决方法
我们可以将产生对象的方法交给工厂去完成,并且此时可以在工厂中判断其权限,设置日志啥的。
接着创建简单工厂

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

public Car createCar(){
// before processing
return new Car();
}

public Broom createBroom(){
return new Broom();
}

public Plane createPlane(){
return new Plane();
}

}

创建好工厂以后,我们只需要直接使用工厂即可

1
2
3
4
public static void main(String[] args) {
SimpleVehicleFactory svf = new SimpleVehicleFactory();
svf.createCar();
}

这就是简单工厂,本质就是一个简单的多态。
但弊端还是要说的:
简单工厂的可扩展性不好
当新添加一种类时,又要在其中加入新的方法,并且 before processing 还是要写死。

工厂方法

此时对于以上情况,我们还可以针对每一种产品做一种工厂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CarFactory
public class CarFactory {
public Moveable create(){
System.out.println("a car created!");
return new Car();
}
}

BroomFactory
public class BroomFactory {
public Moveable create(){
System.out.println("a broom created!");
return new Broom();
}
}

PlaneFactory
public class PlaneFactory {
public Moveable create(){
System.out.println("a plane created!");
return new Plane();
}
}
1
2
3
4
5
Mian
public static void main(String[] args)
{
Moveable moveable = new CarFactory().create();
moveable.go();
}

这样一看是不是就好多了,这就是工厂方法。
为每一个子类建立一个对应的工厂子类,这些工厂子类实现同一个抽象工厂接口。这样,创建不同工厂(交通工具),只需要实现不同的工厂子类。当有新工厂(交通工具)加入时,新建具体工厂继承抽象工厂,而不用修改任何一个类。

抽象工厂

接着我们继续提出要求,要求定制产品一族。
什么意思呢?
上面我们制造了交通工具,接下来我们要求,一个司机开着汽车,吃着面包,吸着烟

代码如下:

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
Car
public class Car{
public void go(){
System.out.println("DiDiDi...");
}
}

Bread
public class Bread{
public void eat(){
System.out.println("bread...");
}
}

Smoking
public class Smoking{
public void act(){
System.out.println("XiXiXi...");
}
}

Main
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.go();
Bread bread = new Bread();
bread.eat();
Smoking smoking = new Smoking();
smoking.act();

}
}

这个时候,我们再提出将这个司机改为原始人。原始人骑着猪,吃着肉,喝着水。
难实现吗?一点也不难,但当我们在实现的时候,Main方法中的定义、调用都需要重写,极其麻烦。

这个时候,我们就需要用到抽象工厂的思想了。

大致思想是这样的,首先,我们创建一个抽象工厂,它会产生三种不同的抽象产品Act、Food、Vehicle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
AbstractFactory
public abstract class AbstractFactory {
abstract Food createFood();
abstract Act createAct();
abstract Vehicle createVehicle();
}

Act
public abstract class Act {
abstract void act();
}

Food
public abstract class Food {
abstract void eat();
}

Vehicle
public abstract class Vehicle {
abstract void go();
}

接着我们再将Car、Bread、Smoking继承Vehicle、Food、Act三个抽象方法。
此时是不是就很明确了。接着我们再创建一个实体类来实现原始人这一族

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
TestFactory
public class TestFactory extends AbstractFactory{
@Override
Food createFood() {
return new Meat();
}

@Override
Act createAct() {
return new Drinking();
}

@Override
Vehicle createVehicle() {
return new Pig();
}
}

Main
public class Main {
public static void main(String[] args) {
AbstractFactory af = new TestFactory();

Vehicle pig = af.createVehicle();
pig.go();
Food meat = af.createFood();
meat.eat();
Act drinking = af.createAct();
drinking.act();
}
}

此时我们并不需要改动大量的代码,只需将
AbstractFactory af = new TestFactory(); TestFactory()改为我们所需要用到的工厂即可。

工厂方法比较方便在于产品单一维度上的扩展,只需加新产品加工厂
而抽象工厂在产品族上扩展时,方便在于产品族的扩展,但是在产品单一维度上扩展时,你的抽象工厂需要加方法,具体工厂要加更多的方法

总结

简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象。
工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量的if-else判断。
抽象工厂:多个工厂类,多个产品抽象类,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。

参考文章:
简单工厂模式、工厂方法模式和抽象工厂模式有何区别?


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!