设计模式——工厂方法模式

以简单工厂模式切入(虽然简单工厂模式不是GoF经典模式之一),介绍工厂方法模式。

简单工厂模式

简单工厂模式(Simple Factory Pattern)又称静态工厂方法(Static Factory Method)模式,属于创建型模式。

简单工厂模式并非GoF 23种经典模式之一。

在简单工厂模式中,可以根据参数的不同返回不同的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

角色

  1. Factory(工厂角色)

    工厂角色即工厂类,是简单工厂模式的核心,负责实现创建所有实例的内部逻辑;

    工厂类可以被外界直接调用,创建所需的产品对象;

    在工厂类中提供了静态的工厂方法factoryMethod(),它返回一个抽象产品类Product,所有的具体产品都是抽象产品的子类。

  2. Product(抽象产品角色)

    抽象产品角色是简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公共接口;

    它的引入将提高系统的灵活性,使得在工厂类中只需定义一个工厂方法,因为所有创建的具体产品对象都是其子类对象。

  3. Concrete Product(具体产品角色)

    具体产品角色是简单工厂模式的创建目标,所有创建的对象都充当这个角色的某个具体类的实例;

    每个具体产品角色都继承了抽象产品角色,需要实现定义在抽象产品中的抽象方法。

类图

image.png

实例

定义一个抽象产品角色

1
2
3
public interface Phone {
public void get();
}

定义两个具体产品,实现抽象产品接口

1
2
3
4
5
6
public class Huawei implements Phone {
@Override
public void get() {
System.out.println("Get the Huawei phone.");
}
}
1
2
3
4
5
6
public class iPhone implements Phone {
@Override
public void get() {
System.out.println("Get the iPhone.");
}
}

再定义一个工厂类负责创建实例

1
2
3
4
5
6
7
8
9
10
11
12
13
public class PhoneFactory {
public static Phone producePhone(String brand) throws Exception {
if (brand.equalsIgnoreCase("Huawei")) {
System.out.println("A Huawei phone have been produced.");
return new Huawei();
} else if (brand.equalsIgnoreCase("iPhone")) {
System.out.println("An iPhone have been produced.");
return new iPhone();
} else {
throw new Exception("Sorry,the product of this brand can not be produced.");
}
}
}

客户端测试类

1
2
3
4
5
6
7
8
9
10
public class Client {
public static void main(String[] args) {
try {
Phone phone = PhoneFactory.producePhone("iphone");
phone.get();
} catch (Exception e) {
e.printStackTrace();
}
}
}

此时运行结果为

1
2
An iPhone have been produced.
Get the iPhone.

若将品牌改为huawei,则结果如下

1
2
A Huawei phone have been produced.
Get the Huawei phone.

若改为一个不存在的品牌,如boluo,则结果如下

1
2
3
java.lang.Exception: Sorry,the product of this brand can not be produced.
at wyp.CreationalPatterns.SimpleFactoryPattern.Factory.PhoneFactory.producePhone(PhoneFactory.java:16)
at wyp.CreationalPatterns.SimpleFactoryPattern.Client.main(Client.java:9)

模式优缺点

优点

  • 免除了客户端直接创建产品对象的责任,仅仅”消费“产品,实现了责任的分割;
  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数;
  • 可以引入配置文件,再不修改客户端代码的情况下更换和增加新的具体产品类。

缺点

  • 工厂类集中了所有产品的创建逻辑,一旦不能正常工作,整个系统都要受到影响;
  • 使用该模式会增加系统中类的个数,一定程度上增加了系统的复杂度和理解难度;
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,不利于系统的维护;
  • 该模式使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构,无法像产品类一样定义一个抽象层,也无法通过具体类进行扩展。

工厂方法模式

工厂方法模式(Factory Method Pattern)又称虚拟构造器(Virtual Constructor)模式或多态工厂(Polymorphic Factory)模式,属于创建型模式。

工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类负责生成具体的产品对象,将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪个具体产品类。

角色

  1. Product(抽象产品)

    抽象产品是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的共同父类或接口。

  2. Concrete Product(具体产品)

    具体产品实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,它们之间一一对应。

  3. Factory(抽象工厂)

    抽象工厂中声明了工厂方法,用于返回一个产品。抽象工厂是工厂方法模式的核心,它与程序无关。任何在模式中创建对象的工厂类都必须实现该接口。

  4. Concrete Factory(具体工厂)

    具体工厂是抽象工厂的子类,实现了抽象工厂中定义的工厂方法,并可由客户调用,返回一个具体产品类的实例。具体工厂中包含与程序密切相关的逻辑,并接受程序调用以创建产品对象。

类图

image.png

实例

定义抽象产品类

1
2
3
public interface Phone {
public void get();
}

定义两个具体产品类

1
2
3
4
5
6
public class Huawei implements Phone {
@Override
public void get() {
System.out.println("Get the Huawei phone.");
}
}
1
2
3
4
5
6
public class iPhone implements Phone {
@Override
public void get() {
System.out.println("Get the iPhone.");
}
}

定义抽象工厂类

1
2
3
public interface PhoneFactory {
public Phone producePhone();
}

定义与具体产品类对应的具体工厂类

1
2
3
4
5
6
7
public class HuaweiFactory implements PhoneFactory {
@Override
public Phone producePhone() {
System.out.println("A Huawei phone have been produced.");
return new Huawei();
}
}
1
2
3
4
5
6
7
public class iPhoneFactory implements PhoneFactory {
@Override
public Phone producePhone() {
System.out.println("An iPhone have been produced.");
return new iPhone();
}
}

客户端测试类

1
2
3
4
5
6
7
8
9
10
11
public class Client {
public static void main(String[] args) {
HuaweiFactory huaweiFactory = new HuaweiFactory();
Phone phone1 = huaweiFactory.producePhone();
phone1.get();

iPhoneFactory iPhoneFactory = new iPhoneFactory();
Phone phone2 = iPhoneFactory.producePhone();
phone2.get();
}
}

此时运行结果为

1
2
3
4
A Huawei phone have been produced.
Get the Huawei phone.
An iPhone have been produced.
Get the iPhone.

若要增加新产品,只需创建一个新的具体产品类实现抽象产品接口,并创建与之对应的具体工厂类实现抽象工厂接口即可。

模式优缺点

优点

  • 在该模式中,工厂方法用来创建客户所需的产品,同时向客户隐藏了哪种具体产品将被实例化这一细节,用户只需关心所需产品对应的工厂,无须关心创建细节与具体产品类的类名;
  • 基于工厂角色和产品角色的多态性设计是该模式的关键,能够使工厂自主确定创建何种产品对象;
  • 在加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,只要添加一个具体工厂和具体产品即可。这样增强了系统的扩展性,完全符合开闭原则。

缺点

  • 添加新产品时需要编写新的具体产品类和与之对应的具体工厂类,系统中类的个数将成对增加,一定程度上增加了系统的复杂度,有额外的类需要编译和运行,给系统带来了额外的开销;
  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

设计模式——工厂方法模式

https://deleter-d.github.io/posts/3827/

作者

亦初

发布于

2022-06-08

更新于

2024-06-19

许可协议

评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...