设计模式|工厂模式

时间:2024-03-27 22:10:04

文章目录

      • 1. 工厂模式的三种实现
      • 2. 简单工厂模式和工厂方法模式示例
      • 3. 抽象工厂模式示例
      • 4. 工厂模式与多态的关系
      • 5. 工程模式与策略模式的关系
      • 6. 面试中可能遇到的问题
        • 6.1 **工厂模式的概念是什么?**
        • 6.2 **工厂模式解决了什么问题?**
        • 6.3 **工厂模式的优点是什么?**
        • 6.4 **工厂模式有哪些不同的实现方式?**
        • 6.5 **举例说明简单工厂模式、工厂方法模式和抽象工厂模式的实现吗?**
        • 6.6 **工厂模式在什么场景下使用比较合适?**
        • 6.7 **使用工厂模式有什么优点?它解决了哪些问题?**
        • 6.8 **工厂模式有什么缺点?在什么情况下不适合使用?**
        • 6.9 **能否举例说明工厂模式在实际项目中的应用场景?**
        • 6.10 **工厂模式和抽象工厂模式有什么区别?**
        • 6.11 **工厂模式和建造者模式有什么区别?它们在解决问题时有何异同?**
        • 6.12 **工厂模式和单例模式之间有什么关系?它们之间有何联系?**
        • 6.13 **在你之前的项目中是否使用过工厂模式?能否分享一些具体的应用经验?**
        • 6.14 **能够列举一些知名的框架或库中使用了工厂模式的例子吗?**
        • 6.15 **工厂模式是如何符合设计原则的?它与哪些设计原则相关?**
      • 附录 demo

在这里插入图片描述
工厂模式是一种常见的设计模式,在Java开发中被广泛应用。它属于创建型设计模式,旨在提供一种封装对象创建过程的方法,使得客户端代码可以与具体创建对象的过程解耦。

1. 工厂模式的三种实现

在Java中,工厂模式通常有三种实现方式:简单工厂模式、工厂方法模式和抽象工厂模式。

  • 简单工厂模式(Simple Factory Pattern)
    • 简单工厂模式通过一个工厂类来创建对象,客户端通过传递不同的参数给工厂类,工厂类根据参数的不同来创建不同的对象实例。
    • 优点是客户端代码简单,隐藏了具体对象的创建细节。
    • 缺点是当需要添加新的产品时,需要修改工厂类的代码,违反了开闭原则。
  • 工厂方法模式(Factory Method Pattern)
    • 工厂方法模式将对象的创建延迟到子类中去实现,即定义一个创建对象的接口,但让子类决定实例化哪个类。
    • 客户端通过调用工厂方法来创建对象,具体的实例化过程由子类负责。
    • 这样可以解决简单工厂模式中的缺点,使得系统更具灵活性和可扩展性。
  • 抽象工厂模式(Abstract Factory Pattern)
    • 抽象工厂模式提供一个接口用于创建一系列相关或依赖对象的家族,而不需要指定具体的类。
    • 与工厂方法模式相比,抽象工厂模式是针对多个产品等级结构的,可以创建不同产品族的全部产品。
    • 这种模式适用于需要在运行时切换不同产品族的场景,但增加新的产品族往往不太容易。

2. 简单工厂模式和工厂方法模式示例

// 简单工厂模式示例
class SimpleFactory {
    public static Product createProduct(String type) {
        if (type.equals("A")) {
            return new ConcreteProductA();
        } else if (type.equals("B")) {
            return new ConcreteProductB();
        } else {
            return null;
        }
    }
}

interface Product {
    void doSomething();
}

class ConcreteProductA implements Product {
    public void doSomething() {
        System.out.println("Product A");
    }
}

class ConcreteProductB implements Product {
    public void doSomething() {
        System.out.println("Product B");
    }
}

// 工厂方法模式示例
interface Factory {
    Product createProduct();
}

class ConcreteFactoryA implements Factory {
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

class ConcreteFactoryB implements Factory {
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

public class Main {
    public static void main(String[] args) {
        // 简单工厂模式示例
        Product productA = SimpleFactory.createProduct("A");
        productA.doSomething();

        // 工厂方法模式示例
        Factory factoryA = new ConcreteFactoryA();
        Product productB = factoryA.createProduct();
        productB.doSomething();
    }
}

以上示例中,简单工厂模式中的 SimpleFactory 负责创建具体产品对象,而工厂方法模式中的 Factory 接口定义了创建产品的方法,具体的产品创建由不同的具体工厂类实现。

3. 抽象工厂模式示例

// 抽象工厂模式示例
interface AbstractFactory {
    AbstractProductA createProductA();
    AbstractProductB createProductB();
}

interface AbstractProductA {
    void doSomething();
}

interface AbstractProductB {
    void doSomething();
}

class ConcreteFactory1 implements AbstractFactory {
    public AbstractProductA createProductA() {
        return new ConcreteProductA1();
    }

    public AbstractProductB createProductB() {
        return new ConcreteProductB1();
    }
}

class ConcreteFactory2 implements AbstractFactory {
    public AbstractProductA createProductA() {
        return new ConcreteProductA2();
    }

    public AbstractProductB createProductB() {
        return new ConcreteProductB2();
    }
}

class ConcreteProductA1 implements AbstractProductA {
    public void doSomething() {
        System.out.println("Product A1");
    }
}

class ConcreteProductA2 implements AbstractProductA {
    public void doSomething() {
        System.out.println("Product A2");
    }
}

class ConcreteProductB1 implements AbstractProductB {
    public void doSomething() {
        System.out.println("Product B1");
    }
}

class ConcreteProductB2 implements AbstractProductB {
    public void doSomething() {
        System.out.println("Product B2");
    }
}

public class Main {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        AbstractProductA productA1 = factory1.createProductA();
        AbstractProductB productB1 = factory1.createProductB();

        productA1.doSomething();
        productB1.doSomething();

        AbstractFactory factory2 = new ConcreteFactory2();
        AbstractProductA productA2 = factory2.createProductA();
        AbstractProductB productB2 = factory2.createProductB();

        productA2.doSomething();
        productB2.doSomething();
    }
}
  • 在这个示例中,AbstractFactory 是抽象工厂接口,定义了创建一组相关产品的方法。
  • ConcreteFactory1ConcreteFactory2 是具体工厂类,分别实现了抽象工厂接口,用于创建一组特定的产品。
  • AbstractProductAAbstractProductB 是抽象产品接口,分别定义了产品 A 和产品 B 的方法。
  • ConcreteProductA1ConcreteProductA2ConcreteProductB1ConcreteProductB2 是具体产品类,分别实现了抽象产品接口,用于提供具体的产品功能。
  • Main 类中,通过创建不同的具体工厂对象来获取不同的产品族,然后调用产品的方法来实现具体的功能。

4. 工厂模式与多态的关系

工厂模式与多态之间有着密切的关系,因为工厂模式往往利用了多态的特性来实现对象的创建和使用。
多态是面向对象编程中的一个重要概念,它允许不同的对象对同一个消息作出不同的响应。在Java中,多态性可以通过继承和接口实现,其中子类或实现了接口的类可以覆写父类或接口中的方法,实现方法的多态性。
工厂模式利用多态性来实现创建对象的过程,具体来说:

  • 工厂方法模式
    • 工厂方法模式中,工厂类定义了一个创建产品的抽象方法,具体的产品创建延迟到具体的子类工厂中去实现。
    • 这里的多态性体现在客户端通过调用工厂方法来创建对象,而不需要关心具体的实现类是哪个,具体的实例化过程由子类负责,从而达到了解耦的目的。
  • 抽象工厂模式
    • 抽象工厂模式中,抽象工厂定义了创建一系列相关或依赖对象的接口,具体的产品族创建由具体的工厂类去实现。
    • 这里的多态性体现在客户端针对抽象工厂编程,而不需要关心具体的工厂类是哪个,具体的工厂类根据客户端的选择来创建不同的产品族。

总的来说,工厂模式通过利用多态性,将对象的创建过程和客户端代码解耦,提高了代码的灵活性和可维护性。在使用工厂模式时,客户端通常面向工厂接口或抽象工厂类编程,从而利用多态性来实现不同产品的创建和使用。

5. 工程模式与策略模式的关系

工厂模式(Factory Pattern)和策略模式(Strategy Pattern)是两种不同类型的设计模式,它们解决了不同的问题,但有时候也可以结合使用,互相配合,以达到更好的设计效果。

  • 工厂模式:
    • 工厂模式旨在提供一种封装对象创建过程的方法,使得客户端代码可以与具体创建对象的过程解耦。
    • 工厂模式根据需要实例化的对象类型,通过工厂类来创建对象,客户端只需要与工厂接口或抽象工厂类交互,而不需要直接与具体产品类交互。
    • 工厂模式通常用于创建对象的场景,比如创建数据库连接、日志记录器等。
  • 策略模式:
    • 策略模式旨在定义一系列算法,并将每个算法封装起来,使它们可以互相替换,从而使算法的变化独立于使用算法的客户端。
    • 策略模式通过定义一个接口或抽象类来封装算法族,然后通过具体的策略类来实现具体的算法,客户端可以根据需要选择不同的策略来使用。
    • 策略模式通常用于算法的变化频繁、需要在运行时动态选择算法或者需要将算法与客户端解耦的场景。

虽然工厂模式和策略模式解决了不同的问题,但在某些情况下它们可以结合使用:

  • 策略模式的工厂:在策略模式中,具体的策略类通常由客户端根据需要进行选择,而这个选择过程也可以由工厂模式来完成。工厂类可以根据某些条件或者策略来实例化具体的策略对象,从而使客户端更加灵活地选择策略。
  • 工厂模式中的策略:在工厂模式中,工厂类可以被视为一种策略的实现,根据客户端的需求选择合适的工厂来创建对象,这样客户端就可以在不同的情况下使用不同的创建策略。

综上所述,工厂模式和策略模式虽然解决了不同的问题,但在一些情况下可以结合使用,以满足更复杂的设计需求。

6. 面试中可能遇到的问题

与工厂模式相关的问题可能涉及到工厂模式的概念、使用场景、实现方式以及与其他设计模式的比较等方面。以下是一些可能会被问及的问题

6.1 工厂模式的概念是什么?
  • 工厂模式是一种创建型设计模式,它提供了一种封装对象创建过程的方法,使得客户端代码可以与具体创建对象的过程解耦。
  • 其核心思想是通过工厂类来创建对象,而不是直接在客户端代码中通过 new 操作符实例化对象。
6.2 工厂模式解决了什么问题?
  • 工厂模式解决了客户端代码与具体对象创建过程之间的耦合问题。它使得客户端不需要知道对象的具体创建细节,只需要通过工厂类来获取所需的对象实例。
6.3 工厂模式的优点是什么?
  • 解耦客户端和具体类的实现,降低了代码的依赖性;
  • 提供了一种统一的接口来创建对象,使得客户端代码更加灵活和可维护;
  • 可以隐藏对象创建的细节,对客户端代码进行了抽象。
6.4 工厂模式有哪些不同的实现方式?

工厂模式有三种主要的实现方式:

  • 简单工厂模式、工厂方法模式和抽象工厂模式。
    • 简单工厂模式通过一个工厂类来创建对象;
    • 工厂方法模式将对象的创建延迟到具体的子类中去实现;
    • 而抽象工厂模式提供一个接口用于创建一系列相关或依赖对象的家族,而不需要指定具体的类。
6.5 举例说明简单工厂模式、工厂方法模式和抽象工厂模式的实现吗?
  • 简单工厂模式示例:一个汽车制造工厂(CarFactory)生产不同型号的汽车(例如:奥迪、宝马、奔驰)。
  • 工厂方法模式示例:一个汽车制造工厂(CarFactory)接口定义了生产汽车的抽象方法,具体的汽车制造工厂(例如:奥迪工厂、宝马工厂、奔驰工厂)继承该接口,并实现了具体的汽车生产方法。
  • 抽象工厂模式示例:一个汽车配件制造工厂(CarPartsFactory)接口定义了生产汽车零件的抽象方法,具体的汽车配件制造工厂(例如:德国工厂、日本工厂)继承该接口,并实现了具体的汽车零件生产方法。
6.6 工厂模式在什么场景下使用比较合适?
  • 工厂模式适用于需要根据不同条件创建不同类型对象的场景,以及对象的创建过程比较复杂、需要隐藏创建细节的场景。
  • 它特别适用于需要创建一系列相关对象或对象族的情况。
6.7 使用工厂模式有什么优点?它解决了哪些问题?
  • 工厂模式的优点包括:解耦、灵活性和可维护性。
  • 它将对象的创建过程集中在一个地方,使得客户端代码更加简洁、灵活,并且易于扩展和维护。
6.8 工厂模式有什么缺点?在什么情况下不适合使用?
  • 工厂模式的缺点是如果产品种类过多,会导致工厂类代码过于复杂;
  • 并且在简单工厂模式在添加新产品时,需要修改工厂类,违反了开闭原则。不适合在产品种类频繁变化的场景中使用。
6.9 能否举例说明工厂模式在实际项目中的应用场景?
  • 工厂模式在实际项目中有许多应用场景,例如在数据库访问框架中,通过工厂模式来创建不同类型的数据库连接对象;在日志记录框架中,通过工厂模式来创建不同类型的日志记录器对象等。
6.10 工厂模式和抽象工厂模式有什么区别?
  • 工厂模式关注于创建单个对象,它提供了一个统一的接口来创建对象;
  • 而抽象工厂模式关注于创建一系列相关或依赖对象的家族,它提供了一个接口来创建不同类型对象的多个系列;
  • 它们适用于不同的场景,工厂模式适用于创建单个对象,而抽象工厂模式适用于创建多个相关对象的家族。
6.11 工厂模式和建造者模式有什么区别?它们在解决问题时有何异同?
  • 区别:
    • 工厂模式用于创建单个对象,它将对象的创建过程封装在一个工厂类中,客户端只需要关注工厂类即可获取所需的对象实例。
    • 建造者模式用于创建复杂对象,将一个复杂对象的构建过程分解为多个简单的步骤,由具体的建造者类负责实现这些步骤,并通过指挥者来组织这些步骤的执行,最终构建出复杂对象。
  • 异同:
    • 相同点:都是创建型设计模式,都涉及对象的创建过程,都可以帮助解决对象的创建过程与客户端代码的解耦问题。
    • 不同点:工厂模式关注于创建单个对象,而建造者模式关注于创建复杂对象,涉及对象构建过程的复杂性和组合方式。
6.12 工厂模式和单例模式之间有什么关系?它们之间有何联系?
  • 工厂模式和单例模式是两种不同类型的设计模式,它们解决了不同的问题,没有直接的关系。
  • 工厂模式是用于创建对象的一种模式,它可以帮助将对象的创建过程与客户端代码解耦。
  • 单例模式是一种创建型设计模式,用于确保一个类只有一个实例,并提供一个全局访问点来访问该实例。
6.13 在你之前的项目中是否使用过工厂模式?能否分享一些具体的应用经验?
  • 是的,我在之前的项目中使用过工厂模式。一个具体的应用场景是在一个电商平台项目中,我们使用工厂模式来创建不同类型的支付方式对象。根据用户选择的支付方式(例如支付宝、微信、银行卡等),工厂类负责创建相应的支付对象,并将其提供给订单处理模块使用。
6.14 能够列举一些知名的框架或库中使用了工厂模式的例子吗?
  • 一些知名的框架或库中使用了工厂模式,
    • 例如 Java 中的 JDBC(Java Database Connectivity) API,它使用工厂模式来创建数据库连接对象;
    • Spring Framework 中的 BeanFactory 和 ApplicationContext 使用工厂模式来创建和管理对象实例;
    • Android 中的 LayoutInflater 使用工厂模式来创建 View 对象等。
6.15 工厂模式是如何符合设计原则的?它与哪些设计原则相关?
  • 工厂模式符合开闭原则(Open Closed Principle)和单一职责原则(Single Responsibility Principle)。
    • 工厂模式使得系统对扩展开放,对修改关闭,当需要添加新的产品时,只需要添加相应的具体产品类和对应的工厂类,而无需修改客户端代码。
    • 工厂模式将对象的创建过程封装在一个单独的类中,实现了对象的创建和使用的分离,符合单一职责原则。

这些问题和答案可以帮助你更好地理解工厂模式,并在面试中给出清晰、准确的回答。

附录 demo

// 电脑接口
interface Computer {
    void display();
}

// 具体产品类:台式电脑
class DesktopComputer implements Computer {
    @Override
    public void display() {
        System.out.println("This is a desktop computer.");
    }
}

// 具体产品类:笔记本电脑
class LaptopComputer implements Computer {
    @Override
    public void display() {
        System.out.println("This is a laptop computer.");
    }
}

// 抽象工厂类:电脑工厂
abstract class ComputerFactory {
    public abstract Computer createComputer();
}

// 具体工厂类:台式电脑工厂
class DesktopComputerFactory extends ComputerFactory {
    @Override
    public Computer createComputer() {
        return new DesktopComputer();
    }
}

// 具体工厂类:笔记本电脑工厂
class LaptopComputerFactory extends ComputerFactory {
    @Override
    public Computer createComputer() {
        return new LaptopComputer();
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建台式电脑
        ComputerFactory desktopFactory = new DesktopComputerFactory();
        Computer desktop = desktopFactory.createComputer();
        desktop.display();

        // 创建笔记本电脑
        ComputerFactory laptopFactory = new LaptopComputerFactory();
        Computer laptop = laptopFactory.createComputer();
        laptop.display();
    }
}