20 设计模式:工厂模式--创建型模式

81 阅读6分钟

创建型模式之:

  • 单例模式
  • 工厂模式
  • 构造者模式
  • 克隆模式

1.工厂模式产生的原因?

工厂模式是一种创建型设计模式,其目的是封装对象的创建过程,以便在整个系统中灵活地创建对象。工厂模式有多种形式,包括简单工厂模式工厂方法模式抽象工厂模式

1. 简单工厂模式的起源:

简单工厂模式是工厂模式中最基本的形式。它的起源可以追溯到基于流水线生产的工业时代。在这个时代,产品的生产被分为多个步骤,每个步骤由专门的工人或机器完成。这种分工使得生产过程更加高效,每个工人或机器专注于自己的任务。

类比到软件设计中,简单工厂模式的思想是将对象的创建过程封装在一个工厂类中,客户端只需要通过工厂类获取所需的对象,而不需要关心对象的创建细节。这种方式使得系统更加灵活,客户端与具体产品的实现解耦。

2.有哪些工厂模式?

前面了解了工厂模式主要分为3种,那举个例子说明下他们的区别:假设我们有一个形状(Shape)的层次结构,包括圆形(Circle)和矩形

2.1工厂模式

在工厂模式中,有一个单一的工厂负责创建不同类型的产品

// 形状接口
interface Shape {
    void draw();
}

// 圆形实现
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Draw a Circle");
    }
}

// 矩形实现
class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Draw a Rectangle");
    }
}

// 形状工厂
class ShapeFactory {
    public Shape createShape(String type) {
        if ("Circle".equalsIgnoreCase(type)) {
            return new Circle();
        } else if ("Rectangle".equalsIgnoreCase(type)) {
            return new Rectangle();
        }
        return null;
    }
}

使用工厂模式:

public class Client {
    public static void main(String[] args) {
        ShapeFactory shapeFactory = new ShapeFactory();
        
        Shape circle = shapeFactory.createShape("Circle");
        circle.draw();  // Draw a Circle

        Shape rectangle = shapeFactory.createShape("Rectangle");
        rectangle.draw();  // Draw a Rectangle
    }
}

2.2工厂方法模式

在工厂方法模式中,每个具体的产品有对应的工厂类。

// 形状工厂接口
interface ShapeFactory {
    Shape createShape();
}

// 圆形工厂
class CircleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Circle();
    }
}

// 矩形工厂
class RectangleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Rectangle();
    }
}

使用工厂方法模式:

public class Client {
    public static void main(String[] args) {
        ShapeFactory circleFactory = new CircleFactory();
        Shape circle = circleFactory.createShape();
        circle.draw();  // Draw a Circle

        ShapeFactory rectangleFactory = new RectangleFactory();
        Shape rectangle = rectangleFactory.createShape();
        rectangle.draw();  // Draw a Rectangle
    }
}

2.3抽象工厂模式

在抽象工厂模式中,有一个抽象工厂接口,每个具体的产品族(例如形状和颜色)都有对应的具体工厂类。

// 形状接口
interface Shape {
    void draw();
}

// 圆形实现
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Draw a Circle");
    }
}

// 矩形实现
class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Draw a Rectangle");
    }
}

// 颜色接口
interface Color {
    void fill();
}

// 红色实现
class Red implements Color {
    @Override
    public void fill() {
        System.out.println("Fill with Red");
    }
}

// 蓝色实现
class Blue implements Color {
    @Override
    public void fill() {
        System.out.println("Fill with Blue");
    }
}

// 抽象工厂接口
interface AbstractFactory {
    Shape createShape();
    Color createColor();
}

// 具体形状工厂
class ShapeFactory implements AbstractFactory {
    @Override
    public Shape createShape() {
        return new Circle();
    }

    @Override
    public Color createColor() {
        return new Red();
    }
}

// 具体形状工厂
class RectangleFactory implements AbstractFactory {
    @Override
    public Shape createShape() {
        return new Rectangle();
    }

    @Override
    public Color createColor() {
        return new Blue();
    }
}

使用抽象工厂模式:

public class Client {
    public static void main(String[] args) {
        AbstractFactory shapeFactory = new ShapeFactory();
        Shape circle = shapeFactory.createShape();
        circle.draw();  // Draw a Circle

        Color red = shapeFactory.createColor();
        red.fill();  // Fill with Red

        AbstractFactory rectangleFactory = new RectangleFactory();
        Shape rectangle = rectangleFactory.createShape();
        rectangle.draw();  // Draw a Rectangle

        Color blue = rectangleFactory.createColor();
        blue.fill();  // Fill with Blue
    }
}
  • 工厂模式通过一个单一的工厂类创建产品。
  • 工厂方法模式每个产品有对应的工厂类,更符合开闭原则。
  • 抽象工厂模式引入了产品族的概念,每个产品族有对应的抽象工厂,更适用于创建一组相关的产品。

可以看出来工厂模式,是针对不同打的复杂对做了区分,在开发中我们需要根据不同的使用场景来选择不同的工厂模式。

3.怎么用工厂模式?

怎么使用工厂模式,其实更重要的一点是知道什么情况下使用工厂模式,设计模式的难点并不是你背不过23中设计模式的名字,或者你不知道他们代码怎么写,而是大多数人不知道什么时候改用设计模式。使用工厂模式的标准是什么呢?

  • 封装变化:创建逻辑有可能变化,封装成工厂类之后,创建逻辑的变更对调用者透明。
  • 代码复用:创建代码抽离到独立的工厂类之后可以复用。
  • 隔离复杂性:封装复杂的创建逻辑,调用者无需了解如何创建对象。
  • 控制复杂度:将创建代码抽离出来,让原本的函数或类职责更单一,代码更简洁。如果创建对象的逻辑比较复杂,可能涉及到多个步骤、条件判断或者依赖关系,这时候使用工厂模式可以将创建对象的逻辑封装在工厂类中,使客户端代码更加简洁。

4.工厂模式有什么缺点?

  1. 类的数量增加: 引入工厂模式会增加类的数量,因为每个具体产品都需要对应一个具体工厂类。这可能导致类的数量庞大,使得项目结构变得复杂,简单的小需求就不需要使用工厂模式了。
  2. 违反开闭原则: 如果需要添加新的产品类型,除了新增产品类外,还需要修改对应的工厂类。这违反了开闭原则,即对扩展开放,对修改关闭。
  3. 抽象层次的过度: 如果产品族中的产品种类很多,可能会导致抽象工厂接口的抽象层次过度复杂,不易理解和维护。
  4. 静态工厂方法无法被子类覆盖: 在使用静态工厂方法时,它们通常不能被子类覆盖,因为静态方法是属于类而不是对象的。
  5. 与依赖注入的冲突: 在某些情况下,工厂模式可能与依赖注入的实践产生冲突。依赖注入通常使用框架来管理对象的创建和注入,而工厂模式可能引入了额外的工厂类。

5.知识扩展(依赖注入)

工厂模式的缺陷就是跟依赖注入产生冲突。那么为什么会产生冲突呢?

5.1 工厂模式和DI容器的区别

  1. DI 容器底层最基本的设计思路就是基于工厂模式的。DI 容器相当于一个大的工厂 类,负责在程序启动的时候,根据配置(要创建哪些类对象,每个类对象的创建需要依赖哪 些其他类对象)事先创建好对象。当应用程序需要使用某个类对象的时候,直接从容器中获 取即可。正是因为它持有一堆对象,所以这个框架才被称为“容器”
  2. DI 容器相对于我们上节课讲的工厂模式的例子来说,它处理的是更大的对象创建工程。上 节课讲的工厂模式中,一个工厂类只负责某个类对象或者某一组相关类对象(继承自同一抽 象类或者接口的子类)的创建,而 DI 容器负责的是整个应用中所有类对象的创建。
  3. DI 容器负责的事情要比单纯的工厂模式要多。比如,它还包括配置的解析、对象生命周期的管理。