创建型设计模式之:简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式
创建型设计模式之:简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式
(一)简单工厂模式
简单工厂模式将对象的实例化过程封装到一个工厂类中,根据输入的条件创建不同类型的对象。
- 角色划分:
- 抽象产品:定义产品的接口
- 具体产品:实现具体的功能
- 工厂类:定义一个静态的工厂方法,负责根据条件创建产品
我们以支付方式为例实现一个简单工厂模式。
// 支付接口(抽象产品)
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) 释放技能,装备:[巨斧, 重甲]}
}