创建型设计模式之:简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式
(一)简单工厂模式
简单工厂模式将对象的实例化过程封装到一个工厂类中,根据输入的条件创建不同类型的对象。
- 角色划分:
- 抽象产品:定义产品的接口
- 具体产品:实现具体的功能
- 工厂类:定义一个静态的工厂方法,负责根据条件创建产品
我们以支付方式为例实现一个简单工厂模式。
java
// 支付接口(抽象产品)
public interface Payment {
void pay(double amount);
}
// 支付宝支付(具体产品)
public class Alipay implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount + "元");
}
}
// 微信支付(具体产品)
public class WechatPay implements Payment {
@Override
public 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 分支
(二)工厂方法模式
工厂方法模式定义工厂接口(声明工厂方法即创建产品的方法)并为每一种具体产品都实现工厂类,将对象的创建过程延迟到子类进行。
- 角色划分:
- 抽象产品:定义产品的接口
- 具体产品:实现具体的功能
- 抽象工厂:工厂类的抽象层,声明工厂方法但不实现具体逻辑
- 具体工厂:为每种具体产品实现一个工厂类,实现工厂方法
我们还是沿用前面的支付方式实现工厂方法模式:
java
// 支付接口(抽象产品)
public interface Payment {
void pay(double amount);
}
// 支付宝支付(具体产品)
public class Alipay implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount + "元");
}
}
// 微信支付(具体产品)
public class WechatPay implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount + "元");
}
}
// 抽象工厂(只负责声明抽象方法,但不做具体实现)
public interface PaymentFactory {
Payment createPayment();
}
// 支付宝支付工厂(具体工厂)
public class AlipayFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new Alipay();
}
}
// 微信支付工厂(具体工厂)
public class WechatPayFactory implements PaymentFactory {
@Override
public 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元
}
}
-
优点:
-
符合开闭原则:如需增加产品类型,只需要增加对应的具体产品类和具体工厂类
-
解耦:客户端只需要依赖抽象工厂和抽象产品,不需要关心具体实现
-
-
缺点:
- 类数量增加:每个产品都对应一个工厂类,导致系统规模膨胀
(三)抽象工厂模式
抽象工厂模式并不像工厂方法模式那样,为每一个产品实现具体工厂类,而是为每一个产品族实现具体工厂类,称为平台工厂。
-
产品体系结构和产品族:
-
产品体系结构是同一类产品的不同实现
- 例如:支付接口,以及下面的微信支付、支付宝支付等实现,构成了支付产品体系结构
-
产品族是同一平台下的不同产品
- 例如:微信平台,以及下面的微信支付、微信贷款等产品,构成了微信产品族
-
-
角色划分:
- 抽象产品:定义产品的接口
- 具体产品:实现具体的功能
- 抽象平台工厂:声明抽象平台下的产品族的工厂方法
- 具体平台工厂:实现具体平台下的产品族的工厂方法
java
// 支付接口
public interface Payment {
void pay(double amount);
}
// 微信支付
public class WechatPayment implements Payment {
@Override
public void pay(double amount) {
System.out.println("微信支付:" + amount + "元");
}
}
// 支付宝支付
public class AlipayPayment implements Payment {
@Override
public void pay(double amount) {
System.out.println("支付宝支付:" + amount + "元");
}
}
// 贷款接口
public interface Loan {
void apply(double amount);
}
// 微信贷款
public class WechatLoan implements Loan {
@Override
public void apply(double amount) {
System.out.println("微信贷款申请:" + amount + "元");
}
}
// 支付宝贷款
public class AlipayLoan implements Loan {
@Override
public void apply(double amount) {
System.out.println("支付宝贷款申请:" + amount + "元");
}
}
// 抽象平台工厂,负责创建平台下的一族产品(包括支付产品与贷款产品)
public interface PlatformFactory {
Payment createPayment();
Loan createLoan();
}
// 微信平台工厂
public class WechatFactory implements PlatformFactory {
@Override
public Payment createPayment() {
return new WechatPayment();
}
@Override
public Loan createLoan() {
return new WechatLoan();
}
}
// 支付宝平台工厂
public class AlipayFactory implements PlatformFactory {
@Override
public Payment createPayment() {
return new AlipayPayment();
}
@Override
public 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()
方法最终调用目标类私有构造器生成对象
- 目标类:私有化构造器,确保只能通过建造者类创建对象,并通过
我们来看如何使用建造者模式构建一个计算机对象:
java
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(); // Computer
computer.show();
}
}
(五)原型模式
原型模式通过复制现有对象(原型)生成新对象,而非通过构造函数初始化。
- 浅拷贝与深拷贝:
- 浅拷贝:复制对象的值类型字段,引用类型字段共享同一内存地址(默认的
Object.clone()
实现) - 深拷贝:递归复制对象的所有字段(包括引用对象),完全独立于原对象,可以通过序列化和反序列化实现
- 浅拷贝:复制对象的值类型字段,引用类型字段共享同一内存地址(默认的
- 角色划分:
- 抽象原型:定义原型公有属性和方法,声明抽象方法,并实现
Cloneable
接口,实现浅拷贝或深拷贝逻辑 - 具体原型:定义具体原型,实现抽象方法
- 原型管理器:负责通过原型注册表管理原型,并克隆出新对象
- 抽象原型:定义原型公有属性和方法,声明抽象方法,并实现
假设游戏中需要快速生成大量相似的敌人,但每个敌人的初始状态(位置、装备)可能不同:
java
// 抽象原型接口(实现 Cloneable)
public abstract class Enemy implements Cloneable {
protected String type;
protected int x;
protected int y;
protected List<String> equipment; // 引用类型字段(测试深拷贝)
public abstract void attack();
// 实现浅拷贝(默认)
@Override
public 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 & Getters
public 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("短剑")); // 默认装备
}
@Override
public 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("巨斧", "重甲"));
}
@Override
public 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) 释放技能,装备:[巨斧, 重甲]
}
}