JAVA设计模式之工厂模式
发布日期:2021-05-06 20:19:26 浏览次数:35 分类:原创文章

本文共 4978 字,大约阅读时间需要 16 分钟。

一 概述

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

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

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:主要解决接口选择的问题。

何时使用:我们明确地计划不同条件下创建不同实例时。

如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

关键代码:创建过程在其子类执行。

应用实例

  • 您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现
  • Hibernate 换数据库只需换方言和驱动就可以

优点

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

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

使用场景

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

注意事项:作为一种创建型模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

二 简单工厂模式

简单工厂模式(Simple Factory Pattern)属于类的创建型模式,又叫静态工厂方法模式(Static FactoryMethod Pattern),是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。简单工厂模式就是通过一个"全能类",根据外界传递的信息来决定创建哪个具体类的对象。

我们将创建一个 Shape 接口和实现 Shape 接口的实体类。下一步是定义工厂类 ShapeFactory。

FactoryPatternDemo 类使用 ShapeFactory 来获取 Shape 对象。它将向 ShapeFactory 传递信息(CIRCLE / RECTANGLE / SQUARE),以便获取它所需对象的类型。
在这里插入图片描述
创建一个接口:
Shape.java

public interface Shape {      void draw();}

创建实现接口的实体类:
Rectangle.java

public class Rectangle implements Shape {       @Override   public void draw() {         System.out.println("Inside Rectangle::draw() method.");   }}

Square.java

public class Square implements Shape {       @Override   public void draw() {         System.out.println("Inside Square::draw() method.");   }}

Circle.java

public class Circle implements Shape {       @Override   public void draw() {         System.out.println("Inside Circle::draw() method.");   }}

创建一个工厂,生成基于给定信息的实体类的对象:
ShapeFactory.java

public class ShapeFactory {          //使用 getShape 方法获取形状类型的对象   public static Shape getShape(String shapeType){         if(shapeType == null){            return null;      }              if(shapeType.equalsIgnoreCase("CIRCLE")){            return new Circle();      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){            return new Rectangle();      } else if(shapeType.equalsIgnoreCase("SQUARE")){            return new Square();      }      return null;   }}

使用该工厂,通过传递类型信息来获取实体类的对象:
FactoryPatternDemo.java

public class FactoryPatternDemo {       public static void main(String[] args) {         //获取 Circle 的对象,并调用它的 draw 方法      Shape shape1 = ShapeFactory.getShape("CIRCLE");      shape1.draw();       //获取 Rectangle 的对象,并调用它的 draw 方法      Shape shape2 = ShapeFactory.getShape("RECTANGLE");      shape2.draw();       //获取 Square 的对象,并调用它的 draw 方法      Shape shape3 = ShapeFactory.getShape("SQUARE");      shape3.draw();   }}

输出结果:

Inside Circle::draw() method.Inside Rectangle::draw() method.Inside Square::draw() method.

优点:工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优化。

缺点:由于工厂类集中了所有实例的创建逻辑,这就直接导致一旦这个工厂出了问题,所有的客户端都会受到牵连;而且由于简单工厂模式的产品是基于一个共同的抽象类或者接口,这样一来,但产品的种类增加的时候,即有不同的产品接口或者抽象类的时候,工厂类就需要判断何时创建何种种类的产品,这就和创建何种种类产品的产品相互混淆在了一起,违背了单一职责,导致系统丧失灵活性和可维护性。而且更重要的是,简单工厂模式违背了“开放封闭原则”,就是违背了“系统对扩展开放,对修改关闭”的原则,因为当我新增加一个产品的时候必须修改工厂类,相应的工厂类就需要重新编译一遍。

总结:简单工厂模式分离产品的创建者和消费者,有利于软件系统结构的优化;但是由于一切逻辑都集中在一个工厂类中,导致了没有很高的内聚性,同时也违背了“开放封闭原则”。另外,简单工厂模式的方法一般都是静态的,而静态工厂方法是无法让子类继承的,因此,简单工厂模式无法形成基于基类的继承树结构。

三 工厂方法模式

工厂方法模式(FACTORY METHOD)是对简单工厂模式的进一步抽象化,符合“开闭原则”,实现了可扩展。工厂方法模式由抽象工厂、具体工厂、抽象产品和具体产品等4个要素构成。

工厂方法模式的主要角色如下:

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

结构图如下:
在这里插入图片描述
实例如下:

抽象产品和具体产品:

//抽象产品公共接口public interface IProduct {       void show();}//具体产品类1class ConcreteProduct1 implements IProduct {       @Override    public void show() {           System.out.println("ConcreteProduct1 show");    }}//具体产品类2class ConcreteProduct2 implements IProduct {       @Override    public void show() {           System.out.println("ConcreteProduct2 show");    }}

抽象工厂和具体工厂:

//抽象工厂类public abstract class AbstractFactory implements {       public abstract IProduct newProduct();}//具体工厂类1class ConcreteFactory1 extends AbstractFactory {       @Override    public void newProduct() {           return new ConcreteProduct1();    }}//具体工厂类2class ConcreteFactory2 extends AbstractFactory {       @Override    public void newProduct() {           return new ConcreteProduct2();    }}

使用如下:

//手机装配工厂public class Client {       public static void main(String[] args) {           AbstractFactory factory1 = new ConcreteFactory1();        IProduct product1 = factory1.newProduct();        product1.show();        AbstractFactory factory2 = new ConcreteFactory2();        IProduct product2 = factory2.newProduct();        product1.show();    }}

优点

  • 可扩展性,添加一个产品不用修改原来的代码,可以添加一个产品的实现类和一个工厂的实现类即可
  • 隔离性,客户端只知道工厂就行,不需要知道创建产品的细节,实现系统解耦

缺点

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

四 抽象工厂模式

上一篇:JAVA设计模式之单例模式
下一篇:JAVA设计模式之代理模式

发表评论

最新留言

表示我来过!
[***.240.166.169]2025年03月28日 11时27分27秒