工厂模式

工厂模式

23种设计模式——GOF(Group of four)

设计模式之工厂模式


定义:在基类中定义创建对象的一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行。

核心作用:实现创建者和调用者分离。

核心本质

  • 实例化对象,用工厂方法代替new操作。
  • 将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。

详细分类

  • 简单工厂模式

    用来生产同一等级结构中的任意产品。(对于增加新的产品,需要修改已有代码)

  • 工厂方法模式

    用来生产同一等级结构中的固定产品。(支持增加任意产品)

  • 抽象工厂模式

    用来生产不同产品族的全部产品。(对于增加新的产品,无能为力,支持增加产品族)

简单工厂模式

模式概述

定义:简单工厂模式也叫静态工厂模式,就是工厂类一般使用静态方法,通过接收的参数不同来返回不同的对象实例。

优点

  • 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
  • 客户端无需知道所创建具体产品的类名,只需知道参数即可。
  • 可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。

缺点

  • 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
  • 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度。
  • 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂。
  • 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。

模式的结构与实现

  • 简单工厂(SimpleFactory):是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。(如下图“CarFactory”)
  • 抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。(如下图“Car”)
  • 具体产品(ConcreteProduct):是简单工厂模式的创建目标。(如下图“Audi”、“Byd”)
  • 调用者(Caller):工厂的调用者。(如下图“Client”)

1
2
3
4
5
// 车的接口
public interface Car {

void run();
}
1
2
3
4
5
6
7
8
// 奥迪车类
public class Audi implements Car {

@Override
public void run() {
System.out.println("奥迪在跑》》》");
}
}
1
2
3
4
5
6
7
8
// 比亚迪车类
public class Byd implements Car {

@Override
public void run() {
System.out.println("比亚迪在跑》》》");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// 车的工厂类
public class CarFactory {

public static Car createCar(String carName) {
if ("Audi".equals(carName)) {
return new Audi();
}
if ("Byd".equals(carName)) {
return new Byd();
}
return null;
}
}
1
2
3
4
5
6
7
8
9
10
// 客户类
public class Client {

public static void main(String[] args) {
Car audi = CarFactory.createCar("audi");
Car byd = CarFactory.createCar("byd");
audi.run(); // 奥迪在跑》》》
byd.run(); // 比亚迪在跑》》》
}
}

应用场景

在以下情况下可以使用简单工厂模式

  • 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  • 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。

示例

Java加密技术

1
2
3
4
5
// 获取不同加密算法的密钥生成器
KeyGenerator keyGen=KeyGenerator.getInstance("DESede");

// 创建不同的密码器
Cipher cp = Cipher.getInstance("DESede");

工厂方法模式

模式概述

定义:工厂方法模式,又称多态性工厂模式或虚拟构造子模式。通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。

与简单工厂模式的区别

  • 工厂方法模式避免了简单工厂模式不完全满足OCP的缺点。
  • 工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类。

优点

  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
  • 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
  • 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。

缺点

  • 类的个数容易过多,增加复杂度。
  • 增加了系统的抽象性和理解难度。
  • 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。

模式的结构与实现

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。(如下图“CarFactory”)
  • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。(如下图“AudiFactory”、“BydFactory”)
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。(如下图“Car”)
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。(如下图“Audi”、“Byd”)
  • 调用者(Caller):工厂的调用者。(如下图“Client”)

1
2
3
4
5
// 车的接口
public interface Car {

void run();
}
1
2
3
4
5
6
7
8
// 奥迪车类
public class Audi implements Car{

@Override
public void run() {
System.out.println("奥迪在跑》》》");
}
}
1
2
3
4
5
6
7
8
// 比亚迪车类
public class Byd implements Car{

@Override
public void run() {
System.out.println("比亚迪在跑》》》");
}
}
1
2
3
4
5
// 车的工厂接口类
public interface CarFactory {

Car createCar();
}
1
2
3
4
5
6
7
8
// 奥迪工厂类
public class AudiFactory implements CarFactory{

@Override
public Car createCar() {
return new Audi();
}
}
1
2
3
4
5
6
7
8
// 比亚迪工厂类
public class BydFactory implements CarFactory{

@Override
public Car createCar() {
return new Byd();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
// 客户类
public class Client {

public static void main(String[] args) {
CarFactory audiFactory = new AudiFactory();
CarFactory bydFactory = new BydFactory();
Car audi = audiFactory.createCar();
Car byd = bydFactory.createCar();
audi.run(); // 奥迪在跑》》》
byd.run(); // 比亚迪在跑》》》
}
}

应用场景

在以下情况下可以使用工厂方法模式

  • 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
  • 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
  • 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

示例

JDBC

1
2
3
4
// 获取不同数据库的Statement进行数据库操作
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");

抽象工厂模式

模式概述

定义:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

与工厂方法模式的区别

  • 工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类。
  • 当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。

优点

  • 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
  • 当需要产品族时,抽象工厂可以保证客户端始终只使用同一个产品的产品族。
  • 抽象工厂增强了程序的可扩展性,当增加一个新的产品族时,不需要修改原代码,满足开闭原则。

缺点

  • 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度。

模式的结构与实现

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法可以创建多个不同等级的产品。(如下图“CarFactory”)
  • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。(如下图“LuxuryCarFactory”、“LowCarFactory”)
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。(如下图“Engine”、“Seat”、“Tyre”)
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。(如下图“LuxuryEngine”、“LuxurySeat”、“LuxuryTyre”、“LowEngine”、“LowSeat”、“LowTyre”)
  • 调用者(Caller):工厂的调用者。(如下图“Client”)

1
2
3
4
5
// 发动机接口
public interface Engine {

void run();
}
1
2
3
4
5
6
7
8
// 高端发动机类 
public class LuxuryEngine implements Engine {

@Override
public void run() {
System.out.println("转的快!");
}
}
1
2
3
4
5
6
7
8
// 低端发动机类
public class LowEngine implements Engine {

@Override
public void run() {
System.out.println("转的慢!");
}
}
1
2
3
4
5
// 座椅接口
public interface Seat {

void message();
}
1
2
3
4
5
6
7
8
// 高端座椅类
public class LuxurySeat implements Seat {

@Override
public void message() {
System.out.println("可以自动按摩!");
}
}
1
2
3
4
5
6
7
8
// 低端座椅类
public class LowSeat implements Seat {

@Override
public void message() {
System.out.println("不能按摩!");
}
}
1
2
3
4
5
// 轮胎接口 
public interface Tyre {

void revolve();
}
1
2
3
4
5
6
7
8
// 高端轮胎类
public class LuxuryTyre implements Tyre {

@Override
public void revolve() {
System.out.println("旋转磨损慢!");
}
}
1
2
3
4
5
6
7
8
// 低端轮胎类
public class LowTyre implements Tyre {

@Override
public void revolve() {
System.out.println("旋转磨损快!");
}
}
1
2
3
4
5
6
7
8
9
// 车的工厂接口类
public interface CarFactory {

Engine createEngine();

Seat createSeat();

Tyre createTyre();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 高端汽车工厂类 
public class LuxuryCarFactory implements CarFactory {

@Override
public Engine createEngine() {
return new LuxuryEngine();
}

@Override
public Seat createSeat() {
return new LuxurySeat();
}

@Override
public Tyre createTyre() {
return new LuxuryTyre();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 低端汽车工厂类  
public class LowCarFactory implements CarFactory {

@Override
public Engine createEngine() {
return new LowEngine();
}

@Override
public Seat createSeat() {
return new LowSeat();
}

@Override
public Tyre createTyre() {
return new LowTyre();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 客户类
public class Client {

public static void main(String[] args) {
getCarParts(new LuxuryCarFactory()); // 转的快! 可以自动按摩! 旋转磨损慢!
getCarParts(new LowCarFactory()); // 转的慢! 不能按摩! 旋转磨损快!
}

public static void getCarParts(CarFactory carFactory) {
Engine engine = carFactory.createEngine();
Seat seat = carFactory.createSeat();
Tyre tyre = carFactory.createTyre();
engine.run();
seat.message();
tyre.revolve();
}
}

应用场景

在以下情况下可以使用抽象工厂模式

  • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
  • 系统中有多于一个的产品族,而每次只使用其中某一产品族。
  • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
  • 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

示例

在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改变时,可以使用抽象工厂模式进行设计。


相关链接:

学习所得,资料、图片部分来源于网络,如有侵权,请联系本人删除。

才疏学浅,若有错误或不当之处,可批评指正,还请见谅!


Your browser is out-of-date!

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

×