前言:
象工厂模式是一种创建型设计模式,它提供了一种方法来创建一组相关或相互依赖的对象,而无需指定具体的类。通过使用抽象工厂模式,我们可以将对象的创建与使用分离,从而使代码更加灵活、可扩展和可维护。
在本博客中,我们将介绍抽象工厂模式的概念、结构和工作原理,以及在实际开发中的应用场景和使用方法。
首先,我们将详细解释什么是工厂模式,以及为什么需要使用抽象工厂模式。我们将探讨其与其他创建型设计模式的区别,并提供一些示例来说明其优势和适用性。
接下来,我们将介绍抽象工厂模式的核心组件,包括抽象工厂接口、具体工厂类和抽象产品接口。我们将详细说明它们各自的职责和关系,并通过代码示例来说明如何实现这些组件。
然后,我们将探讨抽象工厂模式的工作原理。我们将解释如何通过工厂方法来创建产品对象,并且说明如何组合使用多个工厂方法来创建一组相关的产品对象。
最后,我们将介绍抽象工厂模式在实际开发中的应用场景和使用方法。我们将列举一些常见的使用场景,如图形界面库、数据库访问库等,并提供相应的示例代码来说明如何使用抽象工厂模式解决实际问题。
一.介绍抽象工厂模式
1.概念
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种创建一组相关或相互依赖对象的接口,而无需指定具体的类。
抽象工厂模式通过引入抽象工厂和具体工厂的层次结构,使得客户端代码仅与抽象工厂交互,而不必关心具体工厂和产品的细节。这样可以实现客户端代码与具体类的解耦,提高代码的灵活性和可维护性。
2.结构: 抽象工厂模式包含以下角色:
- 抽象工厂(Abstract Factory):定义了创建一组相关产品的方法接口。
- 具体工厂(Concrete Factory):实现了抽象工厂的方法,负责创建具体产品的对象。
- 抽象产品(Abstract Product):定义了产品的共同属性和方法接口。
- 具体产品(Concrete Product):实现了抽象产品的接口,是抽象工厂创建的对象。
3.工作原理:
- 定义抽象工厂接口,其中包含一组创建产品的抽象方法。
- 创建具体工厂类,实现抽象工厂接口,根据业务逻辑创建具体产品的对象。
- 定义抽象产品接口,其中包含产品的共同属性和方法。
- 创建具体产品类,实现抽象产品接口,定义具体产品的属性和方法。
- 在客户端代码中,通过抽象工厂创建产品对象,并调用产品的方法进行业务处理。
4.应用场景: 抽象工厂模式适用于以下情况:
- 系统需要独立于其产品的创建、组合和表示。
- 系统需要一组相关产品对象,并希望统一管理它们的创建过程。
- 系统需要提供一个产品的类库,而不想暴露具体实现的细节。
- 系统需要在运行时切换不同产品族的实现。
5.使用方法:
- 定义抽象工厂接口,声明一组创建产品的抽象方法。
- 创建具体工厂类,实现抽象工厂接口,分别在每个方法中创建具体产品对象。
- 定义抽象产品接口,声明产品的共同属性和方法。
- 创建具体产品类,实现抽象产品接口,定义具体产品的属性和方法。
- 在客户端代码中,通过抽象工厂对象调用创建产品的方法获取产品对象,并进行业务处理。
通过使用抽象工厂模式,可以提高代码的灵活性和可维护性,同时还可以封装产品创建的细节,使得客户端代码与具体类解耦。这种模式常用于框架设计和库开发中,以便为用户提供一组相关的产品对象。
二.具体实例通过抽象工厂模式实现计算器
1.创建Maven工程(按照小编这样操作即可)
2.导入依赖(pom.xml)
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.plugin.version>3.7.0</maven.compiler.plugin.version> <!--添加jar包依赖--> <!--1.spring 5.0.2.RELEASE相关--> <spring.version>5.0.2.RELEASE</spring.version> <!--2.mybatis相关--> <mybatis.version>3.4.5</mybatis.version> <!--mysql--> <mysql.version>5.1.44</mysql.version> <!--pagehelper分页jar依赖--> <pagehelper.version>5.1.2</pagehelper.version> <!--mybatis与spring集成jar依赖--> <mybatis.spring.version>1.3.1</mybatis.spring.version> <!--3.dbcp2连接池相关 druid--> <commons.dbcp2.version>2.1.1</commons.dbcp2.version> <commons.pool2.version>2.4.3</commons.pool2.version> <!--4.log日志相关--> <log4j2.version>2.9.1</log4j2.version> <log4j2.disruptor.version>3.2.0</log4j2.disruptor.version> <slf4j.version>1.7.13</slf4j.version> <!--5.其他--> <junit.version>4.12</junit.version> <servlet.version>4.0.0</servlet.version> <lombok.version>1.18.2</lombok.version> <mybatis.ehcache.version>1.1.0</mybatis.ehcache.version> <ehcache.version>2.10.0</ehcache.version> <redis.version>2.9.0</redis.version> <redis.spring.version>1.7.1.RELEASE</redis.spring.version> <jackson.version>2.9.3</jackson.version> <jstl.version>1.2</jstl.version> <standard.version>1.1.2</standard.version> <tomcat-jsp-api.version>8.0.47</tomcat-jsp-api.version> <commons-fileupload.version>1.3.3</commons-fileupload.version> <hibernate-validator.version>5.0.2.Final</hibernate-validator.version> <shiro.version>1.3.2</shiro.version> </properties>
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>2.0.2-beta</version> <scope>test</scope> </dependency> <!--1.spring相关--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <!--2.mybatis相关--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!--pagehelper分页插件jar包依赖--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>${pagehelper.version}</version> </dependency> <!--mybatis与spring集成jar包依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>${mybatis.spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!--mybatis与ehcache整合--> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>${mybatis.ehcache.version}</version> </dependency> <!--ehcache依赖--> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>${ehcache.version}</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>${redis.version}</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>${redis.spring.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>${jackson.version}</version> </dependency> <!--3.dbcp2连接池相关--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>${commons.dbcp2.version}</version> <exclusions> <exclusion> <artifactId>commons-pool2</artifactId> <groupId>org.apache.commons</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>${commons.pool2.version}</version> </dependency> <!--springmvc依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!--4.log日志相关依赖--> <!-- log4j2日志相关依赖 --> <!-- log配置:Log4j2 + Slf4j --> <!-- slf4j核心包--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> <scope>runtime</scope> </dependency> <!--核心log4j2jar包--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j2.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j2.version}</version> </dependency> <!--用于与slf4j保持桥接--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j2.version}</version> </dependency> <!--web工程需要包含log4j-web,非web工程不需要--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>${log4j2.version}</version> <scope>runtime</scope> </dependency> <!--需要使用log4j2的AsyncLogger需要包含disruptor--> <dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>${log4j2.disruptor.version}</version> </dependency> <!--5.其他--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <!--<scope>test</scope><!––>--> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>${standard.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jsp-api</artifactId> <version>${tomcat-jsp-api.version}</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>${commons-fileupload.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>${hibernate-validator.version}</version> </dependency> <!--shiro依赖--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> </dependencies>
3.构建一个接口(含一个用于进行计算的方法 calculate。该方法接受两个参数, 即 firstNumber 和 secondNumber,并返回一个 double 类型的结果。)
package com.lz.jsq.jk; /** * @author lz * @create 2023-09-11 9:07 */ /** * 包含一个用于进行计算的方法 calculate。该方法接受两个参数, * 即 firstNumber 和 secondNumber,并返回一个 double 类型的结果。 */ public interface Calculator { double calculate(double firstNumber, double secondNumber); }
4.定义具的 Addition
, Subtraction
, Multiplication
和 Division
分别实现(加减乘除):
4.1加法
package com.lz.jsq.jjcc; import com.lz.jsq.jk.Calculator; /** * @author lz * @create 2023-09-11 9:12 */ public class Addition implements Calculator { @Override public double calculate(double firstNumber, double secondNumber) { return firstNumber + secondNumber; } }
4.2减法
package com.lz.jsq.jjcc; import com.lz.jsq.jk.Calculator; /** * @author lz * @create 2023-09-11 9:14 */ public class Subtraction implements Calculator { @Override public double calculate(double firstNumber, double secondNumber) { return firstNumber - secondNumber; } }
4.3乘法
package com.lz.jsq.jjcc; import com.lz.jsq.jk.Calculator; /** * @author lz * @create 2023-09-11 9:14 */ public class Multiplication implements Calculator { @Override public double calculate(double firstNumber, double secondNumber) { return firstNumber * secondNumber; } }
4.4除法
package com.lz.jsq.jjcc; import com.lz.jsq.jk.Calculator; /** * @author lz * @create 2023-09-11 9:15 */ public class Division implements Calculator { @Override public double calculate(double firstNumber, double secondNumber) { if (secondNumber == 0) { throw new IllegalArgumentException("Division by Zero"); } return firstNumber / secondNumber; } }
5.创建一个用于生成计算器实例的抽象工厂 CalculatorFactory
package com.lz.jsq.factory; /** * @author lz * @create 2023-09-11 9:18 */ import com.lz.jsq.jk.Calculator; /** * 创建一个用于生成计算器实例的抽象工厂 */ public interface CalculatorFactory { Calculator createCalculator(); }
6.创建具体的工厂类 AdditionFactory
, SubtractionFactory
, MultiplicationFactory
和 DivisionFactory
来生产相应的计算器实例
6.1加法工厂
package com.lz.jsq.factory; import com.lz.jsq.jjcc.Addition; import com.lz.jsq.jk.Calculator; /** * @author lz * @create 2023-09-11 9:21 */ public class AdditionFactory implements CalculatorFactory { @Override public Calculator createCalculator() { return new Addition(); } }
6.2减法工厂
package com.lz.jsq.factory; import com.lz.jsq.jjcc.Subtraction; import com.lz.jsq.jk.Calculator; /** * @author lz * @create 2023-09-11 9:21 */ public class SubtractionFactory implements CalculatorFactory { @Override public Calculator createCalculator() { return new Subtraction(); } }
6.3乘法工厂
package com.lz.jsq.factory; import com.lz.jsq.jjcc.Multiplication; import com.lz.jsq.jk.Calculator; /** * @author lz * @create 2023-09-11 9:21 */ public class MultiplicationFactory implements CalculatorFactory { @Override public Calculator createCalculator() { return new Multiplication(); } }
6.4除法工厂
package com.lz.jsq.factory; import com.lz.jsq.jjcc.Division; import com.lz.jsq.jk.Calculator; /** * @author lz * @create 2023-09-11 9:21 */ public class DivisionFactory implements CalculatorFactory { @Override public Calculator createCalculator() { return new Division(); } }
7.创建一个 CalculatorApp
类,它将使用 CalculatorFactory
来生成所需类型的 Calculator
实例
package com.lz.jsq.test; import com.lz.jsq.factory.*; import com.lz.jsq.jk.Calculator; import java.util.Scanner; public class CalculatorApp { private CalculatorFactory calculatorFactory; public CalculatorApp(CalculatorFactory calculatorFactory) { this.calculatorFactory = calculatorFactory; } public double calculate(Calculator calculator, double firstNumber, double secondNumber) { return calculator.calculate(firstNumber, secondNumber); } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); boolean shouldContinue = true; while (shouldContinue) { System.out.println("请选择要使用的计算器类型:"); System.out.println("1. 加法"); System.out.println("2. 减法"); System.out.println("3. 乘法"); System.out.println("4. 除法"); CalculatorFactory calculatorFactory = null; int choice = scanner.nextInt(); boolean isValidOption = true; switch (choice) { case 1: calculatorFactory = new AdditionFactory(); break; case 2: calculatorFactory = new SubtractionFactory(); break; case 3: calculatorFactory = new MultiplicationFactory(); break; case 4: calculatorFactory = new DivisionFactory(); break; default: System.out.println("无效的选项"); isValidOption = false; } if (isValidOption) { boolean innerLoopShouldContinue = true; while (innerLoopShouldContinue) { System.out.print("请输入第一个数: "); double firstNumber = scanner.nextDouble(); System.out.print("请输入第二个数: "); double secondNumber = scanner.nextDouble(); CalculatorApp app = new CalculatorApp(calculatorFactory); double result = app.calculate(app.calculatorFactory.createCalculator(), firstNumber, secondNumber); System.out.println("结果为:" + result); System.out.print("是否要继续计算?输入 0 以退出当前运算,输入其他任意数字以继续:"); int continueChoice = scanner.nextInt(); if (continueChoice == 0) { innerLoopShouldContinue = false; } } } System.out.print("是否要继续选择运算类型?输入 0 以退出程序,输入其他任意数字以继续:"); int mainContinueChoice = scanner.nextInt(); if (mainContinueChoice == 0) { shouldContinue = false; } } scanner.close(); } }
8.展示效果图