一、简单工厂
定义
简单工厂模式是一种类的行为型模式,它通过专门的工厂类来创建对象,客户端不直接创建对象,而是通过工厂类来创建
实现示例
饮料产品
// Step 1: 定义抽象产品
interface Drink {
void prepare();
}
// Step 2: 定义具体产品
class Coffee implements Drink {
@Override
public void prepare() {
System.out.println("Preparing Coffee.");
}
}
class Tea implements Drink {
@Override
public void prepare() {
System.out.println("Preparing Tea.");
}
}
class Juice implements Drink {
@Override
public void prepare() {
System.out.println("Preparing Juice.");
}
}
// Step 3: 创建工厂类
class DrinkFactory {
public static Drink createDrink(String drinkType) {
if (drinkType == null || drinkType.isEmpty()) {
throw new IllegalArgumentException("Drink type must not be null or empty.");
}
switch (drinkType.toLowerCase()) {
case "coffee":
return new Coffee();
case "tea":
return new Tea();
case "juice":
return new Juice();
default:
throw new IllegalArgumentException("Unknown drink type: " + drinkType);
}
}
}
// Step 4: 测试客户端代码
public class SimpleFactoryExample {
public static void main(String[] args) {
// 使用工厂创建不同的饮料对象
Drink coffee = DrinkFactory.createDrink("coffee");
Drink tea = DrinkFactory.createDrink("tea");
Drink juice = DrinkFactory.createDrink("juice");
// 调用它们的 prepare 方法
coffee.prepare();
tea.prepare();
juice.prepare();
}
}
简单工厂模式的特点
- 优点:
- 将对象的创建逻辑封装到工厂中,减少客户端对具体实现类的依赖。
- 更易于管理和扩展,添加新产品时只需修改工厂类。
- 缺点:
- 工厂类的职责可能会变得很重,违背单一职责原则。
- 不够灵活,修改工厂逻辑时需要重新编译。
适用场景
简单工厂模式适用于产品数量较少且不会频繁变动,创建逻辑不复杂的场景,比如:
- 创建特定种类的饮料、文档处理器、或者日志记录器。
二、工厂方法模式
定义
工厂方法模式是一种类的行为型模式,它定义了一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法模式让类的实例化推迟到子类。
实现示例
日志记录系统
在不同环境下需要记录日志,比如控制台日志、文件日志等。使用工厂方法模式可以动态选择日志记录器
// Step 1: 定义抽象产品
interface Logger {
void log(String message);
}
// Step 2: 创建控制台日志
class ConsoleLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Console Logger: " + message);
}
}
// Step 2: 创建文件日志
class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("File Logger: " + message + " (logged to a file)");
}
}
// Step 3: 定义抽象工厂
abstract class LoggerFactory {
// 工厂方法,返回具体产品
public abstract Logger createLogger();
// 工厂方法模式中的模板方法
public void logMessage(String message) {
Logger logger = createLogger();
logger.log(message);
}
}
// Step 4: 创建具体工厂
class ConsoleLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
return new ConsoleLogger();
}
}
class FileLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
return new FileLogger();
}
}
// Step 5: 测试客户端代码
public class FactoryMethodExample {
public static void main(String[] args) {
// 使用控制台日志记录器工厂
LoggerFactory consoleLoggerFactory = new ConsoleLoggerFactory();
consoleLoggerFactory.logMessage("This is a console log message.");
// 使用文件日志记录器工厂
LoggerFactory fileLoggerFactory = new FileLoggerFactory();
fileLoggerFactory.logMessage("This is a file log message.");
}
}
工厂方法模式的特点
优点
- 开放/封闭原则:
- 新增具体产品时,只需添加新的具体工厂类,无需修改现有代码
- 单一职责:
- 工厂类负责产品的创建逻辑,产品类只关注自己的功能
- 可扩展性强:
- 当需要新增日志类型(如数据库日志)时,只需添加新的日志类和工厂类即可
缺点
- 每增加一个产品就需要增加一个对应的工厂类,类的数量会增多
使用场景
当系统中有多个产品家族,每个家族中的产品需要有不同的实现时,可以使用工厂方法模式
- 日志框架: 根据环境动态创建控制台、文件、数据库日志记录器
- 数据库连接: 根据不同的数据库类型(MySQL、Oracle)动态创建连接对象
- UI 工具库: 在不同平台(Windows、macOS)生成对应的按钮或窗口
三、抽象工厂模式
定义
抽象工厂模式是一种类的行为型模式,它提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
实现示例
创建不同族的形状和颜色对象
// Step 1: 定义抽象产品接口
interface Shape {
void draw();
}
interface Color {
void fill();
}
// Step 2: 创建具体产品类
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Circle.");
}
}
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a Rectangle.");
}
}
class Red implements Color {
@Override
public void fill() {
System.out.println("Filling with Red color.");
}
}
class Blue implements Color {
@Override
public void fill() {
System.out.println("Filling with Blue color.");
}
}
// Step 3: 定义抽象工厂
interface AbstractFactory {
Shape createShape(String shapeType);
Color createColor(String colorType);
}
// Step 4: 创建具体工厂类
class ShapeFactory implements AbstractFactory {
@Override
public Shape createShape(String shapeType) {
if (shapeType == null) {
return null;
}
switch (shapeType.toLowerCase()) {
case "circle":
return new Circle();
case "rectangle":
return new Rectangle();
default:
throw new IllegalArgumentException("Unknown shape type: " + shapeType);
}
}
@Override
public Color createColor(String colorType) {
// ShapeFactory 不负责创建颜色
return null;
}
}
class ColorFactory implements AbstractFactory {
@Override
public Color createColor(String colorType) {
if (colorType == null) {
return null;
}
switch (colorType.toLowerCase()) {
case "red":
return new Red();
case "blue":
return new Blue();
default:
throw new IllegalArgumentException("Unknown color type: " + colorType);
}
}
@Override
public Shape createShape(String shapeType) {
// ColorFactory 不负责创建形状
return null;
}
}
// Step 5: 创建工厂生成器
class FactoryProducer {
public static AbstractFactory getFactory(String factoryType) {
if (factoryType == null) {
return null;
}
switch (factoryType.toLowerCase()) {
case "shape":
return new ShapeFactory();
case "color":
return new ColorFactory();
default:
throw new IllegalArgumentException("Unknown factory type: " + factoryType);
}
}
}
// Step 6: 测试客户端代码
public class AbstractFactoryPatternExample {
public static void main(String[] args) {
// 获取形状工厂
AbstractFactory shapeFactory = FactoryProducer.getFactory("shape");
Shape circle = shapeFactory.createShape("circle");
Shape rectangle = shapeFactory.createShape("rectangle");
// 调用形状方法
circle.draw();
rectangle.draw();
// 获取颜色工厂
AbstractFactory colorFactory = FactoryProducer.getFactory("color");
Color red = colorFactory.createColor("red");
Color blue = colorFactory.createColor("blue");
// 调用颜色方法
red.fill();
blue.fill();
}
}
优点
- 支持创建多个产品族(如
Shape
和Color
) - 工厂类与客户端代码解耦,增加新产品族时无需修改现有代码
使用场景
- 抽象工厂模式适用于系统需要创建多个相互关联的产品族时,例如主题管理(按钮、窗口、文本框等组件)或游戏开发中的不同种族的单位(如精灵族、兽族)
四、三种模式对比
相同点
- 都属于工厂模式,用于创建对象
- 都将对象的创建和使用分离,提高代码的可维护性和扩展性
不同点 | |
---|---|
简单工厂模式 | 最简单,只有一个工厂类 扩展性差,增加新产品需要修改工厂类 适用于产品种类较少且不会频繁变动的场景 |
工厂方法模式 | 相对复杂,有抽象工厂和具体工厂 扩展性较好,增加新产品只需要添加新的具体工厂类 适用于产品种类较多且可能频繁变动的场景 |
抽象工厂模式 | 最复杂,有抽象工厂、具体工厂、抽象产品和具体产品 扩展性最好,增加新的产品族只需要添加新的具体工厂类,但增加新的产品等级结构较困难 适用于多个产品家族且产品之间有依赖关系的场景 |