java设计模式-工厂模式

文章目录

概念

Java 中的工厂模式是设计模式的一种,主要用于管理对象的创建。它帮助将对象的实例化逻辑从使用对象的逻辑中分离出来,使得代码更加模块化,增加了代码的灵活性和可维护性。工厂模式主要有三种变体:简单工厂模式、工厂方法模式和抽象工厂模式。

一、简单工厂模式

简单工厂模式并不是一个真正的设计模式,但是它是工厂方法模式的一个简化版本。它有一个中心化的工厂类,负责创建其他类的实例。客户端通过传递类型信息给工厂,来获取所需的对象实例。简单工厂模式适合产品种类较少且不会频繁增加的场景,在这种情况下,可以通过简单工厂模式简化对象的创建过程,同时保持客户端和具体产品解耦。

1、角色和职责

角色

  1. 工厂类(Factory Class):这是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的职责是提供一个创建对象的方法,客户端通过调用这个方法来创建对象。这个方法通常根据传递给它的参数来决定创建哪种类型的对象。
  2. 抽象产品(Abstract Product):这是一个接口或抽象类,定义了产品的公共接口。在具体实现类中,这些接口或抽象类的方法将被实现。
  3. 具体产品(Concrete Product):继承或实现抽象产品的类,工厂类将创建并返回这些具体产品的实例。每个具体产品都会实现抽象产品定义的接口,表示不同类型的产品对象。

职责

  1. 工厂类的职责
  • 根据客户端的请求,决定创建哪种具体产品的实例。
  • 隐藏了创建产品的具体逻辑,客户端不需要知道具体产品类的名字,只需要知道工厂类。
  • 可能包含选择合适产品类并创建其实例的逻辑。
  1. 抽象产品的职责
  • 声明所有具体产品都应实现的接口,定义了产品的规范,确保所有具体产品的一致性。
  1. 抽象产品的职责
  • 实现或继承抽象产品的接口或类,定义具体产品的具体属性和方法。
  • 每个具体产品都将提供不同的实现,这些实现通过工厂类创建并返回给客户端。

2、优点

  • 帮助实现了代码的解耦,客户端不需要直接创建对象,而是通过工厂类来做这件事,减少了客户端和产品对象之间的依赖。
  • 添加新的产品类时,只需要扩展工厂类即可,无需修改已有的客户端代码,提高了系统的可维护性。

3、缺点

  • 当添加新产品时,需要修改工厂类,违反了开闭原则。
  • 工厂类的职责过重,随着产品种类的增加,工厂方法会变得越来越复杂。

4、适用场景

  • 创建的对象数量不多且不会频繁变化。
  • 客户端不关心对象的创建过程。

5、示例1

  1. 定义一个接口或者抽象类(Product):所有具体的产品实现这个接口或继承这个抽象类,这些产品在概念上是相关的,但实现细节不同。
  2. 创建具体的产品类(Concrete Products):实现或继承第一重定义接口或抽象类。每个具体产品都包含特定于产品的实现代码。
  3. 创建工厂(Factory):包含一个或多个方法,这些方法用于根据输入参数的不同,决定创建并返回哪一种具体产品的实例。客户端调用这个方法而不是直接创建产品对象。
  4. 客户端调用工厂类的方法 :客户端使用工厂类,而不是直接实例化产品对象。客户端不需要知道如何创建这些对象,只需知道工厂方法的参数。
    假设我们有一个应用,需要根据用户的需求创建不同类型的日志记录器,比如文件日志记录器和数据库日志记录器。

第一步:定义产品接口

java 复制代码
public interface Logger {
    void log(String message);
}

第二步:创建具体产品类

java 复制代码
public class FileLogger implements Logger {
    public void log(String message) {
        System.out.println("Logging message to a file: " + message);
    }
}

public class DatabaseLogger implements Logger {
    public void log(String message) {
        System.out.println("Logging message to the database: " + message);
    }
}

第三步:创建工厂类

java 复制代码
public class LoggerFactory {
    public static Logger getLogger(String type) {
        if (type.equalsIgnoreCase("file")) {
            return new FileLogger();
        } else if (type.equalsIgnoreCase("database")) {
            return new DatabaseLogger();
        } else {
            throw new IllegalArgumentException("Unknown logger type");
        }
    }
}

第四步:客户端调用工厂类的方法

java 复制代码
public class Client {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger("file");
        logger.log("This is a message.");

        logger = LoggerFactory.getLogger("database");
        logger.log("This is another message.");
    }
}

6、示例2

步骤1:创建产品接口和具体产品类,首先定义一个产品接口FileViewer和几个具体的产品类TextViewerImageViewerVideoViewer,每个产品类实现 FileViewer接口。

java 复制代码
interface FileViewer {
    void display();
}

class TextViewer implements FileViewer {
    public void display(){
        System.out.println("Display text file...");
    }
}

class ImageViewer implements FileViewer {
    public void display(){
        System.out.println("Display image file...");
    }
}

class VideoViewer implements FileViewer {
    public void display(){
        System.out.println("Display video file...");
    }
}

步骤2:创建一个简单工厂类ViewerFactory,它有一个静态方法 createViewer,根据文件类型返回对应的视图对象。

java 复制代码
class ViewerFactory {
    public static FileViewer createViewer(String fileType){
        switch(fileType){
            case: "text"
                return new TextViewer();
            case: "image"
                return new ImageViewer();
            case: "video"
                return new VideoViewer();
            default:
                throw new IllegalArgumentException("Unsupported file type:" + fileType);
        }
    }
}

步骤3:客户端使用工厂类

java 复制代码
public class FactoryClient{
    public static void main(String[] args){
        FileViewer viewer = ViewerFactory.createViewer("text");
        viewer.display();
        viewer = ViewerFactory.createViewer("image");
        viewer.display();
    }
}

7、示例3

java 复制代码
public interface ICar {
    void drive();
}

public class Bmw implements ICar {
    public void drive(){
        System.out.println("Bmw");
    }
}

public class Audi implements ICar{
    public void drive(){
        // audi
    }
}

public class Benz implements ICar{
    public void drive(){
        // benz
    }
}

public class SimpleFactory{
    private SimpleFactory(){ }

    public static ICar createCar(String carType){
        if("BMW".equalsIgnoreCase(carType)){
            return new Bmw();
        }else if ("Audi".equalsIgnoreCase(carType)){
            return new Audi();
        }else if ("Benz".equalsIgnoreCase(carType)){
            return new Benz();
        }else {
            return null;
        }
    }
}
java 复制代码
public class FactoryClient{
    public static void main(String[] args){
        SimpleFactory.create("BMW").drive();
    }
}

8、示例4:枚举

java 复制代码
public enum EnumCarFactory{
    BMW{
        @Override
        public ICar create(){
            return new Bmw();
        }
    },
    AUDI{
        @Override
        public ICar create(){
            return new Audi();
        }
    },
    BENZ{
        @Override
        public ICar create(){
            return new Benz();
        }
    }


    // abstarct 修饰,强制每个枚举实现该方法
    public abstarct ICar create();
}
java 复制代码
public class FactoryClient{
    public static void main(String[] args){
        EnumCarFactory.AUDI.create().drive();
    }
}

9、示例5:反射

java 复制代码
public class EnhancedSimpleFactory{
    private EnhancedSimpleFactory() {}

    public static <T> T create(Class<? extend T> clazz){
        T obj = null;
        try {
            obj = (T) Class.forName(clazz.getName()).newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e){
            e.printStackTrace();
        }
        return obj;
    }
}
java 复制代码
public class FactoryClient{
    public static void main(String[] args){
        // 入参类路径也可来自配置文件、数据库等,因此更具灵活性。
       EnhancedSimpleFactory.create(Benz.class).drive()
    }
}

二、工厂方法模式

工厂方法模式是设计模式中的一种,属于创建型模式的一部分。它定义了一个创建对象的接口,但是让实现这个接口的类来决定实例化哪一个类。工厂方法让类的实例化延迟到其子类进行。

1、角色和职责

角色

  1. 抽象产品(Abstract Product):这是一个接口或抽象类,定义了产品的公共接口。所有的产品类都需要实现这个接口,这样的设计使得所有产品类在概念上是相同的。
  2. 具体产品(Concrete Product):实现或继承自抽象产品的类。每个具体产品都会定义具体的业务操作,这些是客户端所期望的功能。
  3. 抽象工厂(Creator):这是一个接口或抽象类,声明了工厂方法,这个方法返回一个抽象产品类型。抽象工厂使得创建对象的实现延迟到其子类中进行。
  4. 具体工厂(Concrete Creator):继承或实现抽象工厂的类。具体工厂负责创建一个或多个具体产品的实例,决定实例化哪个产品类。每个具体工厂都必须实现抽象工厂定义的工厂方法。

职责

  1. 抽象产品(Product)的职责
  • 定义所有具体产品必须实现的接口,确保所有产品类在概念上是一致的,提供了产品实例的通用属性和方法。
  1. 具体产品(Concrete Product)的职责
  • 实现抽象产品接口定义的操作,代表特定实现的产品对象。
  1. 抽象工厂(Creator)的职责
  • 声明工厂方法,返回一个产品实例。工厂方法通常是抽象的,需要子类实现。
  • 可以提供工厂方法的默认实现,返回一个默认的产品对象。
  1. 具体工厂(Concrete Creator)的职责
  • 重写或实现抽象工厂中定义的工厂方法,以创建和返回具体产品的实例。具体工厂知道应当实例化哪一个具体产品类。
  • 直接与客户端代码交互,提供创建产品的具体实现。

2、优点

  • 提供了代码解耦:在工厂方法模式中,客户端不需要知道它所创建实例的类的具体类名,只需知道对应的工厂即可。这有助于系统在不修改客户端代码的情况下引入新的类,提高了系统的灵活性。
  • 扩展性高:添加新的产品类不需要修改已有的工厂类,只需添加相应的具体产品类和对应的具体工厂即可,符合开闭原则。
  • 强制隔离了创建和使用代码:用户只关心产品的接口而不关心具体类的实现,工厂方法也使得用户代码和具体类的实现解耦。
  • 提供了一种扩展的策略,比简单工厂模式更有弹性。

3、缺点

  • 可能导致类的数量增加:每增加一个产品,都需要增加一个具体产品类和一个具体工厂类,这会导致系统类的数量成倍增加,增加了系统的复杂性。
  • 系统的抽象性和理解难度增加:需要引入抽象层,在客户端代码中既包含抽象也包含具体类的操作,对系统结构和抽象层的理解将会更加复杂。

4、使用场景

  • 当一个类不知道它所必须创建的对象的类的时候:在工厂方法模式中,类的实例化延迟到其子类。
  • 当一个类希望由它的子类来指定创建对象的时候:工厂方法使类的实例可以在运行时更加灵活地增加新的类型。
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪个帮助子类是委托者这一信息局部化时

5、示例1

考虑一个日志记录器的例子,我们需要根据不同的场景(例如文件日志记录和数据库日志记录)创建不同类型的日志记录器。

步骤 1: 定义产品接口

java 复制代码
public interface Logger {
    void log(String message);
}

步骤 2: 创建具体产品类

java 复制代码
public class FileLogger implements Logger {
    public void log(String message) {
        System.out.println("File logger: " + message);
    }
}

public class DatabaseLogger implements Logger {
    public void log(String message) {
        System.out.println("Database logger: " + message);
    }
}

步骤 3: 定义工厂接口

java 复制代码
public interface LoggerFactory {
    Logger createLogger();
}

步骤 4: 创建具体工厂类

java 复制代码
public class FileLoggerFactory implements LoggerFactory {
    public Logger createLogger() {
        // 可以在这里添加创建FileLogger前的逻辑,如配置加载等
        return new FileLogger();
    }
}

public class DatabaseLoggerFactory implements LoggerFactory {
    public Logger createLogger() {
        // 可以在这里添加创建DatabaseLogger前的逻辑,如配置加载等
        return new DatabaseLogger();
    }
}

步骤 5: 客户端代码

java 复制代码
public class FactoryMethodDemo {
    public static void main(String[] args) {
        LoggerFactory factory;
        Logger logger;
        
        // 使用文件日志记录器
        factory = new FileLoggerFactory();
        logger = factory.createLogger();
        logger.log("This is a file log message.");

        // 使用数据库日志记录器
        factory = new DatabaseLoggerFactory();
        logger = factory.createLogger();
        logger.log("This is a database log message.");
    }
}

这个示例中,**LoggerFactory** 是工厂接口,**FileLoggerFactory** **DatabaseLoggerFactory**是具体的工厂类,它们负责创建对应的产品类实例。客户端代码仅与接口 **LoggerFactory** **Logger** 交互,具体使用哪个日志记录器类的决定权交给了具体的工厂类,这样就实现了创建逻辑与使用逻辑的分离,提高了代码的灵活性和扩展性。

三、抽象工厂模式

抽象工厂模式是一种创建型设计模式,它提供了一种方式,可以封装一组具有共同主题的单独的工厂而无需指定它们的具体类。这种模式是围绕一个超级工厂创建其他工厂的概念。该超级工厂又称为其他工厂的工厂。在抽象工厂模式中,接口是负责创建相关对象的工厂,不需要明确指定它们的类。

1、角色和职责

角色

  1. 抽象工厂(Abstract Factory):提供一个接口,用于创建一系列相关或相互依赖的对象,而不需要指定它们具体的类。
  2. 具体工厂(Concrete Factory):实现抽象工厂接口的具体类。每个具体工厂都能够按照工厂接口定义的方式生产一组具体产品。不同的具体工厂对应于不同的产品变体。
  3. 抽象产品(Abstract Product):为一系列产品对象声明一个接口。在抽象接口中声明了所有产品必须实现的操作。
  4. 具体产品(Concrete Product):抽象工厂模式所创建的实际产品对象,每个具体产品都是一个抽象产品的实现。
  5. 客户端(Client):仅使用由抽象工厂和抽象产品提供的接口声明的方法。客户端通过抽象接口操纵实例,从而使得与应用程序的具体类解耦。

职责

  1. 抽象工厂(Abstract Factory)的职责
  • 声明了一组用于创建一系列相关或相互依赖对象的方法,每个方法对应于一种产品。
  1. 具体工厂(Concrete Factory)的职责
  • 实现抽象工厂的方法来创建具体的产品对象。每个具体工厂对应于特定的产品变体,并创建具有特定实现的产品对象。
  1. 抽象产品(Abstract Product)的职责
  • 为一类产品声明接口。在该接口中声明了所有具体产品都必须实现的操作。
  1. 具体产品(Concrete Product)的职责
  • 实现抽象产品接口的具体类。定义了一个将被相应的具体工厂创建的产品对象。
  1. 客户端(Client)的职责
  • 仅调用从抽象工厂和抽象产品类中派生的接口。客户端通过这些接口与工厂创建的对象交互,从而使具体的工厂和产品类与客户端代码解耦。

2、优点

  • 分离接口和实现:客户端代码通过接口操作实例,从而解耦了客户端和具体类的依赖。
  • 增加新的具体工厂和产品族很方便:无需修改现有系统,符合开闭原则,系统的可扩展性好。
  • 强化了程序的抽象层次:抽象工厂模式通过使用产品族,能够更方便地进行替换产品系列,增加了程序的灵活性和可维护性。

3、缺点

  • 难以支持新种类的产品:如果需要添加新产品,则必须修改抽象工厂的接口,这将涉及到抽象工厂类及其所有子类的修改,违背了开闭原则。
  • 增加了系统的抽象性和复杂度:引入了多层接口和类,系统的学习和理解难度增加。

4、适用场景

  • 当系统中的产品有多于一个的产品族,而系统只消费其中某一族的产品时:抽象工厂可以为访问某一产品族的产品提供接口。
  • 当一个产品族中的多个对象被设计成一起工作时,它可以保证客户端始终只使用同一个产品族中的对象。
  • 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。

5、示例1

假设我们正在开发一个跨平台的UI库,我们需要为不同的操作系统(如Windows和Mac)创建不同风格的UI元素(如按钮和复选框)。我们将使用抽象工厂模式来解决这个问题。

步骤 1: 创建抽象产品类和具体产品类

java 复制代码
public interface Button {
    void paint();
}

public class WinButton implements Button {
    public void paint() {
        System.out.println("Render a button in Windows style");
    }
}

public class MacButton implements Button {
    public void paint() {
        System.out.println("Render a button in MacOS style");
    }
}

public interface Checkbox {
    void paint();
}

public class WinCheckbox implements Checkbox {
    public void paint() {
        System.out.println("Render a checkbox in Windows style");
    }
}

public class MacCheckbox implements Checkbox {
    public void paint() {
        System.out.println("Render a checkbox in MacOS style");
    }
}

步骤 2: 创建抽象工厂类和具体工厂类

java 复制代码
public interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

public class WinFactory implements GUIFactory {
    public Button createButton() {
        return new WinButton();
    }
    
    public Checkbox createCheckbox() {
        return new WinCheckbox();
    }
}

public class MacFactory implements GUIFactory {
    public Button createButton() {
        return new MacButton();
    }
    
    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

步骤 3: 客户端代码

java 复制代码
public class Application {
    private Button button;
    private Checkbox checkbox;

    public Application(GUIFactory factory) {
        button = factory.createButton();
        checkbox = factory.createCheckbox();
    }

    public void paint() {
        button.paint();
        checkbox.paint();
    }
}

public class Demo {
    public static void main(String[] args) {
        GUIFactory factory = new WinFactory();
        Application app = new Application(factory);
        app.paint();

        factory = new MacFactory();
        app = new Application(factory);
        app.paint();
    }
}

在这个例子中,GUIFactory 是一个抽象工厂,负责定义创建UI元素的接口。WinFactoryMacFactory 是具体的工厂,实现了GUIFactory接口,分别创建Windows风格和Mac风格的UI元素。客户端代码依赖于抽象工厂和抽象产品的接口,从而可以在不关心具体产品细节的情况下,使用不同的产品族。这就是抽象工厂模式的强大之处。

相关推荐
Good Note9 分钟前
Golang的静态强类型、编译型、并发型
java·数据库·redis·后端·mysql·面试·golang
我就是我3521 小时前
记录一次SpringMVC的406错误
java·后端·springmvc
向哆哆1 小时前
Java应用程序的跨平台性能优化研究
java·开发语言·性能优化
ekkcole1 小时前
windows使用命令解压jar包,替换里面的文件。并重新打包成jar包,解决Failed to get nested archive for entry
java·windows·jar
handsomestWei2 小时前
java实现多图合成mp4和视频附件下载
java·开发语言·音视频·wutool·图片合成视频·视频附件下载
全栈若城2 小时前
03 Python字符串与基础操作详解
java·开发语言·python
伯牙碎琴2 小时前
二、Spring Framework基础:IoC(控制反转)和DI(依赖注入)
java·spring·log4j
菲力蒲LY2 小时前
输入搜索、分组展示选项、下拉选取,全局跳转页,el-select 实现 —— 后端数据处理代码,抛砖引玉展思路
java·前端·mybatis
南宫生2 小时前
力扣每日一题【算法学习day.130】
java·学习·算法·leetcode
!!!5253 小时前
Java实现斗地主-做牌以及对牌排序
java·算法