~/app/articles/NORMAL

cat article/38.md

原型模式 (Prototype) 全面讲解

学习笔记
设计模式
原型模式
Java
面向对象
克隆
对象创建
设计模式讲解

本文全面讲解了原型模式,包括其定义、适用场景、结构以及示例代码。文章深入探讨了原型模式在Java中的应用,并提供了具体的实现示例。

date: 2025-06-22T19:44:00 tags:

  • 复习
  • Java
  • 设计模式
  • 面向对象

原型模式 (Prototype) 全面讲解


1. 什么是原型模式?

原型模式是创建型设计模式,通过**复制现有对象(原型)**来创建新对象,而非通过new实例化。

  • 核心思想:克隆(Clone)代替重新构造,适用于创建成本高或构造过程复杂的对象。
  • 类比:细胞分裂(基于现有细胞复制新细胞)。

🔹 适用场景

  • 对象创建开销大(如数据库查询结果、复杂计算对象)。
  • 需要动态配置对象的初始状态(如游戏中的敌人/NPC生成)。

2. 为什么需要原型模式?

问题场景

假设有一个Enemy类,构造时需要从数据库加载属性:

// 传统方式:每次new都需重复耗时操作
Enemy enemy1 = new Enemy();  // 耗时:数据库查询+初始化
Enemy enemy2 = new Enemy();  // 再次耗时...

解决方案

通过克隆第一个实例快速创建后续对象:

Enemy prototype = new Enemy();  // 仅第一次耗时
Enemy enemy2 = prototype.clone();  // 直接复制内存,极快

3. 原型模式的结构

角色说明

  1. Prototype(抽象原型):声明克隆方法的接口(Java中通常是Cloneable)。
  2. ConcretePrototype(具体原型):实现克隆方法的具体类。

4. 示例代码(游戏敌人克隆)

步骤1:实现Cloneable接口

public class Enemy implements Cloneable {
    private String type;
    private int health;
    private List<String> weapons;

    public Enemy(String type, int health) {
        this.type = type;
        this.health = health;
        this.weapons = loadWeaponsFromDatabase(); // 模拟耗时操作
        System.out.println("耗时:从数据库加载武器数据");
    }

    // 模拟复杂初始化
    private List<String> loadWeaponsFromDatabase() {
        return Arrays.asList("Sword", "Shield");
    }

    // 关键:重写clone()方法
    @Override
    public Enemy clone() {
        try {
            Enemy cloned = (Enemy) super.clone(); // 浅拷贝
            cloned.weapons = new ArrayList<>(this.weapons); // 手动深拷贝可变字段
            return cloned;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

    public void attack() {
        System.out.println(type + "攻击!武器:" + weapons);
    }
}

步骤2:客户端调用

public class Client {
    public static void main(String[] args) {
        // 原始对象(构造耗时)
        Enemy original = new Enemy("Dragon", 100);
        
        // 通过克隆快速创建新对象
        Enemy clone1 = original.clone();
        Enemy clone2 = original.clone();

        original.attack();  // Dragon攻击!武器:[Sword, Shield]
        clone1.attack();    // Dragon攻击!武器:[Sword, Shield]
    }
}

5. 关键点总结

🔹 浅拷贝 vs 深拷贝

类型实现方式特点
浅拷贝super.clone()复制基本类型字段,引用类型字段共享内存(修改会影响原对象)。
深拷贝手动复制引用类型完全独立的对象,需递归处理所有引用字段(如集合、自定义类)。

🔹 原型模式的优点

  • 性能高:避免重复初始化耗时操作。
  • 动态配置:克隆后可修改部分属性(如clone.setHealth(50))。

🔹 注意事项

  • Java的Cloneable是标记接口,需主动重写clone()方法。
  • 深拷贝需谨慎处理循环引用问题。

6. 互动实践

问题1:以下代码是浅拷贝还是深拷贝?

@Override
public Enemy clone() {
    try {
        return (Enemy) super.clone();
    } catch (CloneNotSupportedException e) {
        throw new AssertionError();
    }
}

答案:浅拷贝!weapons字段(List)与原对象共享内存。

问题2:如何实现Weapon类的深拷贝?

任务:假设Enemy包含Weapon对象:

public class Weapon implements Cloneable {
    private String name;
    @Override
    public Weapon clone() { /* 你的代码 */ }
}
// 修改Enemy.clone()实现完全深拷贝

7. 考试练习题

题目1(概念题)

原型模式的核心目的是什么?
A. 隐藏对象创建细节
B. 通过复制现有对象创建新实例
C. 限制类的实例化次数
D. 替代继承

答案:B


题目2(代码填空)

补全原型模式的深拷贝代码:

public class Student implements Cloneable {
    private String name;
    private List<String> courses;

    @Override
    public Student clone() {
        try {
            Student cloned = (Student) super.clone();
            cloned.courses = ____;  // 填空1(深拷贝courses)
            return cloned;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

答案:new ArrayList<>(this.courses)


题目3(设计题)

用原型模式设计一个Document类,支持克隆:

  • 属性:title(字符串)、pages(List<String>)
  • 要求:实现深拷贝,并说明如何避免循环引用问题。
$ comments --list (0)

// not signed in


// no comments yet