Java设计模式之 - 原型模式
·
什么是原型模式?
原型模式通过复制(克隆)一个已有的对象来创建新对象,而不是通过new关键字创建。它就像是复印机:
- 你有一份原稿(原型对象)
- 放进复印机,得到一份一模一样的副本(克隆对象)
- 可以在副本上修改,不影响原稿
主要解决什么问题?
原型模式主要解决以下问题:
- 对象创建成本高:有些对象的创建过程很复杂或耗时
- 需要大量相似对象:避免重复进行复杂的初始化
- 对象状态复杂:希望保留对象的部分状态
- 动态创建:在运行时不知道具体类型
- 避免子类泛滥:工厂模式需要为每个产品创建工厂类
何时使用原型模式?
当你遇到以下场景时,考虑使用原型模式:
- 对象初始化操作复杂(如数据库查询、网络请求)
- 需要创建大量相似对象(如游戏中的子弹、粒子)
- 对象状态需要保留(如撤销操作时的快照)
- 系统需要独立于对象的创建方式
- 运行时动态指定要创建的对象类型
原型模式的优点
- 性能提升:直接克隆比new一个对象并初始化要快
- 简化创建:隐藏了对象创建的复杂性
- 动态配置:可以在运行时克隆对象
- 减少子类:不需要为每个产品创建工厂类
- 保存状态:可以方便地保存对象的状态快照
原型模式的缺点
- 克隆复杂:涉及深克隆和浅克隆的问题
- 循环引用:对象间存在循环引用时克隆困难
- 需要实现Cloneable接口:Java的克隆机制有局限性
- 可能过度设计:简单对象没必要用原型模式
代码示例:多种原型模式实现
1. Java浅克隆(实现Cloneable接口)
// 必须实现Cloneable接口
class Employee implements Cloneable {
private String name;
private int age;
private String department;
private List<String> skills; // 引用类型
public Employee(String name, int age, String department) {
this.name = name;
this.age = age;
this.department = department;
this.skills = new ArrayList<>();
System.out.println("Employee构造函数被调用: " + name);
}
public void addSkill(String skill) {
skills.add(skill);
}
// 重写clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 浅克隆
}
// Getter和Setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public List<String> getSkills() { return skills; }
@Override
public String toString() {
return "Employee{name='" + name + "', age=" + age +
", department='" + department + "', skills=" + skills +
", hashCode=" + hashCode() + "}";
}
}
// 客户端
public class ShallowCloneDemo {
public static void main(String[] args) throws CloneNotSupportedException {
System.out.println("=== 浅克隆示例 ===\n");
// 创建原型对象
Employee original = new Employee("张三", 30, "开发部");
original.addSkill("Java");
original.addSkill("Spring");
System.out.println("原型对象: " + original);
System.out.println("原型对象技能列表hashCode: " + original.getSkills().hashCode());
System.out.println();
// 克隆对象
Employee cloned = (Employee) original.clone();
System.out.println("克隆对象: " + cloned);
System.out.println("克隆对象技能列表hashCode: " + cloned.getSkills().hashCode());
System.out.println("\n=== 浅克隆的问题 ===");
// 修改克隆对象的技能(会影响原型对象!)
cloned.addSkill("MySQL");
System.out.println("修改后原型对象: " + original);
System.out.println("修改后克隆对象: " + cloned);
System.out.println("原型和克隆共享同一个技能列表!");
}
}
2. 深克隆(手动实现)
// 深克隆实现
class DeepEmployee implements Cloneable {
private String name;
private int age;
private String department;
private List<String> skills; // 引用类型
public DeepEmployee(String name, int age, String department) {
this.name = name;
this.age = age;
this.department = department;
this.skills = new ArrayList<>();
}
public void addSkill(String skill) {
skills.add(skill);
}
// 深克隆
@Override
protected Object clone() throws CloneNotSupportedException {
// 先调用父类的clone(复制基本类型)
DeepEmployee cloned = (DeepEmployee) super.clone();
// 手动克隆引用类型
cloned.skills = new ArrayList<>(this.skills);
return cloned;
}
public List<String> getSkills() { return skills; }
@Override
public String toString() {
return "DeepEmployee{name='" + name + "', skills=" + skills +
", skillsHash=" + skills.hashCode() + "}";
}
}
// 客户端
public class DeepCloneDemo {
public static void main(String[] args) throws CloneNotSupportedException {
System.out.println("=== 深克隆示例 ===\n");
DeepEmployee original = new DeepEmployee("李四", 25, "测试部");
original.addSkill("Python");
original.addSkill("Selenium");
System.out.println("原型对象: " + original);
// 深克隆
DeepEmployee cloned = (DeepEmployee) original.clone();
System.out.println("克隆对象: " + cloned);
System.out.println("\n=== 修改克隆对象 ===");
cloned.addSkill("JMeter");
System.out.println("修改后原型对象: " + original);
System.out.println("修改后克隆对象: " + cloned);
System.out.println("原型和克隆技能列表独立!");
}
}
3. 通过序列化实现深克隆
import java.io.*;
// 通过序列化实现深克隆(需要实现Serializable)
class SerializableEmployee implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private List<String> skills;
private Address address; // 另一个引用类型
public SerializableEmployee(String name, int age) {
this.name = name;
this.age = age;
this.skills = new ArrayList<>();
}
public void setAddress(Address address) {
this.address = address;
}
public void addSkill(String skill) {
skills.add(skill);
}
// 通过序列化实现深克隆
public SerializableEmployee deepClone() {
try {
// 写入字节流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
// 读取字节流
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (SerializableEmployee) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "SerializableEmployee{name='" + name + "', age=" + age +
", skills=" + skills + ", address=" + address +
", hashCode=" + hashCode() + "}";
}
}
class Address implements Serializable {
private static final long serialVersionUID = 1L;
private String city;
private String street;
public Address(String city, String street) {
this.city = city;
this.street = street;
}
@Override
public String toString() {
return "Address{city='" + city + "', street='" + street + "'}";
}
}
// 客户端
public class SerializationCloneDemo {
public static void main(String[] args) {
System.out.println("=== 序列化实现深克隆 ===\n");
SerializableEmployee original = new SerializableEmployee("王五", 28);
original.addSkill("Java");
original.addSkill("Redis");
original.setAddress(new Address("北京", "朝阳区"));
System.out.println("原型对象: " + original);
// 序列化克隆
SerializableEmployee cloned = original.deepClone();
System.out.println("克隆对象: " + cloned);
System.out.println("\n=== 验证深克隆 ===");
cloned.addSkill("MongoDB");
cloned.setAddress(new Address("上海", "浦东新区"));
System.out.println("修改后原型对象: " + original);
System.out.println("修改后克隆对象: " + cloned);
}
}
实际应用场景
-
Java标准库:
Object.clone()方法java.util.Date.clone()java.util.ArrayList.clone()
-
框架中使用:
- Spring中的原型作用域Bean
- 原型模式在单元测试中创建测试对象
-
游戏开发:
- 创建大量敌人、子弹、特效
- 游戏地图中的重复元素
-
文档系统:
- 文档模板
- 图形绘制中的重复图形
总结
原型模式通过克隆已有对象来创建新对象,避免了复杂的初始化过程,提高了对象创建的效率。
更多推荐
所有评论(0)