当前位置: 首页 > news >正文

创建型设计模式之:简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式

创建型设计模式之:简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式

(一)简单工厂模式

简单工厂模式将对象的实例化过程封装到一个工厂类中,根据输入的条件创建不同类型的对象。

  • 角色划分:
    • 抽象产品:定义产品的接口
    • 具体产品:实现具体的功能
    • 工厂类:定义一个静态的工厂方法,负责根据条件创建产品

我们以支付方式为例实现一个简单工厂模式。

// 支付接口(抽象产品)
public interface Payment {void pay(double amount);
}// 支付宝支付(具体产品)
public class Alipay implements Payment {@Overridepublic void pay(double amount) {System.out.println("使用支付宝支付:" + amount + "元");}
}// 微信支付(具体产品)
public class WechatPay implements Payment {@Overridepublic void pay(double amount) {System.out.println("使用微信支付:" + amount + "元");}
}// 支付工厂(负责创建具体产品)
public class PaymentFactory {// 工厂方法,根据条件创建产品public static Payment createPayment(String type) {if ("alipay".equalsIgnoreCase(type)) {return new Alipay();} else if ("wechat".equalsIgnoreCase(type)) {return new WechatPay();} else {throw new IllegalArgumentException("不支持的支付类型");}}
}// 客户端
public class Client {public static void main(String[] args) {// 通过工厂创建支付对象,面向接口而不是具体实现编程Payment alipay = PaymentFactory.createPayment("alipay");alipay.pay(100.0);  // 输出:使用支付宝支付:100.0元Payment wechatPay = PaymentFactory.createPayment("wechat");wechatPay.pay(200.0);  // 输出:使用微信支付:200.0元}
}
  • 优点:

    • 解耦:将对象的创建与使用分离,客户端不需要关心具体实现类
    • 集中管理:新增或修改产品时只需要调整工厂类
  • 缺点:

    • 违反开闭原则:新增或修改产品类需要调整工厂类代码的 if-else 分支

(二)工厂方法模式

工厂方法模式定义工厂接口(声明工厂方法即创建产品的方法)并为每一种具体产品都实现工厂类,将对象的创建过程延迟到子类进行。

  • 角色划分:
    • 抽象产品:定义产品的接口
    • 具体产品:实现具体的功能
    • 抽象工厂:工厂类的抽象层,声明工厂方法但不实现具体逻辑
    • 具体工厂:为每种具体产品实现一个工厂类,实现工厂方法

我们还是沿用前面的支付方式实现工厂方法模式:

// 支付接口(抽象产品)
public interface Payment {void pay(double amount);
}// 支付宝支付(具体产品)
public class Alipay implements Payment {@Overridepublic void pay(double amount) {System.out.println("使用支付宝支付:" + amount + "元");}
}// 微信支付(具体产品)
public class WechatPay implements Payment {@Overridepublic void pay(double amount) {System.out.println("使用微信支付:" + amount + "元");}
}// 抽象工厂(只负责声明抽象方法,但不做具体实现)
public interface PaymentFactory {Payment createPayment();
}// 支付宝支付工厂(具体工厂)
public class AlipayFactory implements PaymentFactory {@Overridepublic Payment createPayment() {return new Alipay();}
}// 微信支付工厂(具体工厂)
public class WechatPayFactory implements PaymentFactory {@Overridepublic Payment createPayment() {return new WechatPay();}
}// 客户端
public class Client {public static void main(String[] args) {// 如需增加支付方式,只需要增加对应的具体产品类和具体工厂类,直接修改客户端即可,符合开闭原则PaymentFactory paymentFactory = new AlipayFactory();Payment payment = paymentFactory.createPayment();payment.pay(100.0);  // 输出:使用支付宝支付:100.0元}
}
  • 优点:

    • 符合开闭原则:如需增加产品类型,只需要增加对应的具体产品类和具体工厂类

    • 解耦:客户端只需要依赖抽象工厂和抽象产品,不需要关心具体实现

  • 缺点:

    • 类数量增加:每个产品都对应一个工厂类,导致系统规模膨胀

(三)抽象工厂模式

抽象工厂模式并不像工厂方法模式那样,为每一个产品实现具体工厂类,而是为每一个产品族实现具体工厂类,称为平台工厂。

  • 产品体系结构和产品族:

    • 产品体系结构是同一类产品的不同实现

      • 例如:支付接口,以及下面的微信支付、支付宝支付等实现,构成了支付产品体系结构
    • 产品族是同一平台下的不同产品

      • 例如:微信平台,以及下面的微信支付、微信贷款等产品,构成了微信产品族
  • 角色划分:

    • 抽象产品:定义产品的接口
    • 具体产品:实现具体的功能
    • 抽象平台工厂:声明抽象平台下的产品族的工厂方法
    • 具体平台工厂:实现具体平台下的产品族的工厂方法
// 支付接口
public interface Payment {void pay(double amount);
}// 微信支付
public class WechatPayment implements Payment {@Overridepublic void pay(double amount) {System.out.println("微信支付:" + amount + "元");}
}// 支付宝支付
public class AlipayPayment implements Payment {@Overridepublic void pay(double amount) {System.out.println("支付宝支付:" + amount + "元");}
}// 贷款接口
public interface Loan {void apply(double amount);
}// 微信贷款
public class WechatLoan implements Loan {@Overridepublic void apply(double amount) {System.out.println("微信贷款申请:" + amount + "元");}
}// 支付宝贷款
public class AlipayLoan implements Loan {@Overridepublic void apply(double amount) {System.out.println("支付宝贷款申请:" + amount + "元");}
}// 抽象平台工厂,负责创建平台下的一族产品(包括支付产品与贷款产品)
public interface PlatformFactory {Payment createPayment();Loan createLoan();
}// 微信平台工厂
public class WechatFactory implements PlatformFactory {@Overridepublic Payment createPayment() {return new WechatPayment();}@Overridepublic Loan createLoan() {return new WechatLoan();}
}// 支付宝平台工厂
public class AlipayFactory implements PlatformFactory {@Overridepublic Payment createPayment() {return new AlipayPayment();}@Overridepublic Loan createLoan() {return new AlipayLoan();}
}// 客户端
public class Client {public static void main(String[] args) {PlatformFactory platformFactory = new WechatFactory();Payment payment = platformFactory.createPayment();Loan loan = platformFactory.createLoan();payment.pay(100.0);loan.apply(100.0);}
} 
  • 开闭原则的倾斜性:
    • 新增产品族,只需要增加对应的具体产品和平台工厂类,不需要改动原有代码,符合开闭原则
    • 新增产品体系结构,需要修改抽象平台工厂和所有的具体平台工厂实现,不符合开闭原则

(四)建造者模式

建造者模式主要用于分步骤构建复杂对象,分离构造过程和表示,并通过链式调用增强可读性,避免客户端构造器参数爆炸。

  • 角色划分:
    • 目标类:私有化构造器,确保只能通过建造者类创建对象,并通过 builder() 方法提供建造者的访问入口
    • 建造者类:目标类的静态内部类,私有化构造器,通过链式方法设置可选参数,并通过 build() 方法最终调用目标类私有构造器生成对象

我们来看如何使用建造者模式构建一个计算机对象:

public class Computer {// 计算机类的属性private String cpu;private String ram;private String hardDisk;private String screen;// 私有化构造器,并通过传入建造者创建对象,这个构造器将会在建造者的 build() 方法中被调用private Computer(Builder builder) {this.cpu = builder.cpu;this.ram = builder.ram;this.hardDisk = builder.hardDisk;this.screen = builder.screen;}// 提供建造者的访问入口public static Builder builder() {return new Builder();}// 业务方法public void show() {System.out.println("cpu: " + cpu);System.out.println("ram: " + ram);System.out.println("hardDisk: " + hardDisk);System.out.println("screen: " + screen);}// 静态内部建造者类,负责通过链式方法构建目标对象public static class Builder {private String cpu;private String ram;private String hardDisk;private String screen;// 私有化构造器,这个构造器将会在目标类的 builder() 方法中被调用private Builder() {}// 通过一系列链式方法设置目标对象的属性,这些方法都会返回构造器对象,用于最后调用 build() 方法public Builder cpu(String cpu) {this.cpu = cpu;return this;}public Builder ram(String ram) {this.ram = ram;return this;}public Builder hardDisk(String hardDisk) {this.hardDisk = hardDisk;return this;}public Builder screen(String screen) {this.screen = screen;return this;}// 返回目标对象public Computer build() {return new Computer(this);}}
}public class Client {public static void main(String[] args) {Computer computer = Computer.builder() // Builder.cpu("i7") // Builder.ram("16G") // Builder.hardDisk("512G") // Builder.screen("15.6") // Builder.build(); // Computercomputer.show();}
}

(五)原型模式

原型模式通过复制现有对象(原型)生成新对象,而非通过构造函数初始化。

  • 浅拷贝与深拷贝:
    • 浅拷贝:复制对象的值类型字段,引用类型字段共享同一内存地址(默认的 Object.clone() 实现)
    • 深拷贝:递归复制对象的所有字段(包括引用对象),完全独立于原对象,可以通过序列化和反序列化实现
  • 角色划分:
    • 抽象原型:定义原型公有属性和方法,声明抽象方法,并实现 Cloneable 接口,实现浅拷贝或深拷贝逻辑
    • 具体原型:定义具体原型,实现抽象方法
    • 原型管理器:负责通过原型注册表管理原型,并克隆出新对象

假设游戏中需要快速生成大量相似的敌人,但每个敌人的初始状态(位置、装备)可能不同:

// 抽象原型接口(实现 Cloneable)
public abstract class Enemy implements Cloneable {protected String type;protected int x;protected int y;protected List<String> equipment;  // 引用类型字段(测试深拷贝)public abstract void attack();// 实现浅拷贝(默认)@Overridepublic Enemy clone() {try {return (Enemy) super.clone();} catch (CloneNotSupportedException e) {throw new RuntimeException("克隆失败", e);}}// 深拷贝实现(需手动重写)public Enemy deepClone() {Enemy cloned = this.clone();cloned.equipment = new ArrayList<>(this.equipment);  // 深拷贝引用字段return cloned;}// Setters & Getterspublic void setPosition(int x, int y) {this.x = x;this.y = y;}public void addEquipment(String item) {this.equipment.add(item);}
}// 具体原型:普通敌人
public class NormalEnemy extends Enemy {public NormalEnemy() {type = "普通敌人";equipment = new ArrayList<>(List.of("短剑"));  // 默认装备}@Overridepublic void attack() {System.out.printf("[%s] 在位置(%d, %d) 发动攻击,装备:%s\n", type, x, y, equipment);}
}// 具体原型:Boss敌人
public class BossEnemy extends Enemy {public BossEnemy() {type = "Boss";equipment = new ArrayList<>(List.of("巨斧", "重甲"));}@Overridepublic void attack() {System.out.printf("[%s] 在位置(%d, %d) 释放技能,装备:%s\n", type, x, y, equipment);}
}import java.util.HashMap;
import java.util.Map;public class EnemyRegistry {private static Map<String, Enemy> prototypes = new HashMap<>();static {// 预注册原型prototypes.put("normal", new NormalEnemy());prototypes.put("boss", new BossEnemy());}// 获取克隆对象public static Enemy getEnemy(String type) {Enemy prototype = prototypes.get(type);if (prototype == null) {throw new IllegalArgumentException("未知敌人类型");}return prototype.deepClone();  // 深拷贝返回}// 动态添加原型public static void addPrototype(String key, Enemy enemy) {prototypes.put(key, enemy);}
}// 客户端
public class GameClient {public static void main(String[] args) {// 从注册表克隆敌人Enemy enemy1 = EnemyRegistry.getEnemy("normal");enemy1.setPosition(10, 20);enemy1.addEquipment("盾牌");  // 修改克隆体的装备enemy1.attack(); // 输出:[普通敌人] 在位置(10, 20) 发动攻击,装备:[短剑, 盾牌]Enemy enemy2 = EnemyRegistry.getEnemy("boss");enemy2.setPosition(50, 30);enemy2.attack(); // 输出:[Boss] 在位置(50, 30) 释放技能,装备:[巨斧, 重甲]}
}

相关文章:

  • Oracle Recovery Tools修复ORA-00742、ORA-600 ktbair2: illegal inheritance故障
  • 路由器的基础配置全解析:静态动态路由 + 华为 ENSP 命令大全
  • 3D模型文件格式之《STL格式介绍》
  • 知识蒸馏和迁移学习的区别
  • Cannot read properties of null (reading ‘classList‘)
  • A2A与MCP之间的简单理解
  • 【Google上包前APK自检】
  • 深入理解网络原理:UDP协议详解
  • 【Linux】Vim文本编辑器
  • Java使用IText7动态生成带审批文本框的PDF文档
  • 【Nova UI】十、打造组件库第一个组件-图标组件(下):从.svg 到 SVG Vue 组件的高效蜕变✨
  • LeetCode 1780 判断一个数字是否可以表示成三的幂的和
  • AI超级智能体项目教程(二)---后端项目初始化(设计knif4j接口文档的使用)
  • PHP框架在微服务迁移中能发挥什么作用?
  • 测试流程?
  • 猫咪如厕检测与分类识别系统系列【十三】猫咪进出事件逻辑及日志优化【下】
  • 计算机组成原理:指令系统
  • 10前端项目----商品详情页/滚轮行为
  • Java多线程同步有哪些方法?
  • top 命令里面可以看到进程哪些状态?
  • 民生访谈|宝妈宝爸、毕业生、骑手……上海如何为不同人群提供就业保障
  • 央行副行长:我们在研究丰富政策工具箱,将适时推出增量政策
  • 央行副行长:增强外汇市场韧性,坚决对市场顺周期行为进行纠偏
  • 广州海关原党委委员、副关长刘小威被开除党籍
  • 百岁太极拳大师、陈氏太极拳第十一代嫡宗传人陈全忠逝世
  • 伊朗港口爆炸已造成25人死亡,灭火行动已近尾声