JAVA设计模式(2) - 工厂模式

简单工厂模式

介绍

定义

简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。 —— 百度百科

结构

简单工厂模式

​ 如上图,简单工厂模式包含以下三种角色:

  • Product:产品

    该类是抽象类,为所有产品的抽象父类,它描述了所有产品应有的公共接口

  • ConcreteProduct:具体产品

    该类是抽象父类的具体实现,它定义了每个产品的独立使用方法

  • Factory:工厂

    该类负责生产产品,也就是提供各个产品的创建方法

特点

  • 需要创建的对象较少
  • 根据自定不同参数即可创建不同对象,屏蔽了内部细节

应用

产品类

我们定义抽象产品为“动物”,动物都会发声,因此代码如下:

1
2
3
4
5
public abstract class Animal {

protected void saySth() {}

}

具体产品类

我们定义具体产品为”猫” “狗”,并继承动物的抽象类,如下:

猫:

1
2
3
4
5
6
7
public class Cat extends Animal {
@Override
protected void saySth() {
super.saySth();
System.out.println("喵喵喵");
}
}

狗:

1
2
3
4
5
6
7
public class Dog extends Animal {
@Override
protected void saySth() {
super.saySth();
System.out.println("汪汪汪");
}
}

工厂类

我们定义工厂可以生产出这些动物,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Factory {

public static void main(String[] args) {
Animal animal = Factory.create(NAME_CAT);
animal.saySth();
}

public static final String NAME_CAT = "cat";
public static final String NAME_DOG = "dog";

public static Animal create(String name) {
switch (name) {
case NAME_CAT:
return new Cat();
case NAME_DOG:
return new Dog();
default:
throw new IllegalArgumentException("错误的名字!");
}
}
}

其中Factory.create(NAME_CAT)就是“简单工厂模式”的核心方法。

总结

优点

  • 客户端无需知道具体产品的内部细节,只需知道生产产品的名字即可生产,实现了消费和生产的解耦
  • 通过配置,可以在不修改客户端的情况下修改或新增具体产品类,提高了灵活性

缺点

  • 工厂类集中了所有产品的创建逻辑,比较臃肿
  • 违背“开放-关闭 原则”,一旦添加新产品就必须要修改工厂类逻辑
  • 工厂类使用了静态方法,不能被继承和重构,不利于后续扩展

优化

​ 由于该模式下,工厂类包含了所有实例的创建逻辑,违反了高内聚职责分配原则,当具体产品类不断增多的时候,工厂类的单一逻辑就显得臃肿而复杂。所以我们引入了工厂方法模式。

工厂方法模式

介绍

定义

工厂方法模式(Factory method pattern)是一种实现了“工厂”概念的面向对象设计模式。就像其他创建型模式一样,它也是处理在不指定对象具体类型的情况下创建对象的问题。

工厂方法模式的实质是“定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。

——维基百科

结构

工厂方法模式

​ 如上图,工厂方法模式包含以下四种角色:

  • Product:产品

    该类是抽象类,为所有产品的抽象父类,它描述了所有产品应有的公共接口

  • ConcreteProduct:具体产品

    该类是抽象父类的具体实现,它定义了每个产品的独立使用方法

  • Factory:工厂

    该类是抽象类,为所有工厂的抽象父类,它描述了所有工厂应有的公共接口

  • ConcreteFactory:具体工厂

    该类是抽象父类的具体实现,它负责生产产品,也就是提供产品的创建方法

###特点

  • 工厂类不再负责所有产品的创建,而是拓展子类,将具体的创建工作分发给不同的子类,即允许在不修改工厂角色的情况下新增产品

  • 封装了产品细节,只需知道具体工厂即可创建所需产品

  • 符合『开放-封闭原则

应用

产品类

我们定义产品类为动物,动物都会发声,因此代码如下:

1
2
3
4
5
public abstract class Animal {

protected void saySth() {};

}

具体产品类

我们在这里创建两个品种的动物,分别是:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class OrangeCat extends Animal {
@Override
protected void saySth() {
System.out.println("喵喵喵");
}
}

public class GermanDog extends Animal {
@Override
protected void saySth() {
System.out.println("汪汪汪");
}
}

工厂类

我们定义抽象的工厂类,提供一个公共接口create()

1
2
3
4
5
public abstract class Factory {

protected Animal create() {};

}

具体工厂类

有了工厂类的公共接口后,我们即可拓展出自己细分的工厂,如CatFactoryDogFactory

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

@Override
protected Animal create() {
return new OrangeCat();
}
}
}

public class DogFactory extends Factory {

@Override
protected Animal create() {
return new GermanDog();
}
}
}

创建好了这些单独工厂和产品之后,我们即可以方便地使用了:

1
2
3
4
5
6
7
8
9
10
public class Main {

public static void main(String[] args) {
Factory factory = new CatFactory();
Animal animal = factory.create();
animal.saySth();

new DogFactory().create().saySth();
}
}

打印如下:

1
2
3
4
喵喵喵
汪汪汪

Process finished with exit code 0

总结

优点

  • 工厂方法创建了用户所需的产品,且隐藏了具体实例化的细节,用户只需关心工厂,而无需关心具体的创建细节
  • 具有多态的特性,所有工厂都由同一抽象父类拓展而成
  • 加入新产品时,无需修改抽象接口或父类,只需添加一个具体工厂和产品即可

缺点

  • 添加新产品时,对应要添加新的具体工厂类,代码量较多
  • 抽象层较多,增加了系统的复杂度

###优化

抽象工厂模式

介绍

定义

结构

抽象工厂模式

特点

应用

当具体产品类较多时,抽象工厂模式就派上用场了,比如我们在这里创建两种类别,四个品种的动物,分别是:

BritishCat GermanDog
OrangeCat GlodenDog

我们先定义由 Animal 拓展而出的 Cat ,Dog 抽象类:

1
2
public abstract class Cat extends Animal {}
public abstract class Dog extends Animal {}

再定义“具体产品”,也就是四种不同动物的品种:

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
public class BritishCat extends Cat {
@Override
protected void saySth() {
System.out.println("喵呜喵");
}
}

public class OrangeCat extends Cat {
@Override
protected void saySth() {
System.out.println("喵喵喵");
}
}

public class GermanDog extends Dog {
@Override
protected void saySth() {
System.out.println("汪汪汪");
}
}

public class GoldenDog extends Dog {
@Override
protected void saySth() {
System.out.println("汪呜汪");
}
}

工厂类

我们定义抽象的工厂类,提供一个公共接口create()

1
2
3
4
5
6
7
public abstract class Factory {

protected Animal create(String name) {
throw new IllegalArgumentException("错误的创建方法!");
};

}

具体工厂类

有了工厂类的公共接口后,我们即可拓展出自己细分的工厂,如CatFactoryDogFactory

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

public static final String NAME_ORANGE_CAT = "orangeCat";
public static final String NAME_BRITISH_CAT = "britishCat";

@Override
protected Animal create(String name) {
switch (name) {
case NAME_ORANGE_CAT:
return new OrangeCat();
case NAME_BRITISH_CAT:
return new BritishCat();
default:
throw new IllegalArgumentException("不支持的猫类品种");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class DogFactory extends Factory {

public static final String NAME_GERMAN_DOG = "germanDog";
public static final String NAME_GOLDEN_DOG = "goldenDog";

@Override
protected Animal create(String name) {
switch (name) {
case NAME_GERMAN_DOG:
return new GermanDog();
case NAME_GOLDEN_DOG:
return new GoldenDog();
default:
throw new IllegalArgumentException("不支持的狗类品种");
}
}
}

创建好了这些工厂和产品之后,我们既能方便使用,又能轻松拓展了:

1
2
3
4
5
6
7
8
9
10
public class Main {

public static void main(String[] args) {
Factory factory = new CatFactory();
Animal animal = factory.create(CatFactory.NAME_ORANGE_CAT);
animal.saySth();

new DogFactory().create(DogFactory.NAME_GERMAN_DOG).saySth();
}
}

打印如下:

1
2
3
4
喵喵喵
汪汪汪

Process finished with exit code 0

总结

优点

缺点

优化

参考链接:https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/creational.html

https://www.jianshu.com/p/83ef48ce635b

https://www.hollischuang.com/archives/1391

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×