【设计模式】创建型-原型模式

文章目录

  • 前言
  • 一、概念
  • 二、核心思想
  • 三、Java代码实现
    • [1. 定义原型对象(游戏角色抽象类,实现克隆接口)](#1. 定义原型对象(游戏角色抽象类,实现克隆接口))
    • [2. 定义具体原型(战士角色+法师角色)](#2. 定义具体原型(战士角色+法师角色))
    • [3. 浅克隆测试代码(默认克隆方式)](#3. 浅克隆测试代码(默认克隆方式))
    • [4. 深克隆实现(解决浅克隆引用类型共享问题)](#4. 深克隆实现(解决浅克隆引用类型共享问题))
    • [5. 扩展:原型管理器(统一管理原型,简化克隆)](#5. 扩展:原型管理器(统一管理原型,简化克隆))
  • 四、优缺点
    • [1. 优点](#1. 优点)
    • [2. 缺点](#2. 缺点)
  • 五、应用场景
  • 六、注意事项
  • 总结

前言

在AI时代,代码的编写可以被大模型辅助甚至替代,但程序员真正的核心竞争力是技术思维------设计模式这类沉淀了数十年的"内功心法",决定了代码的可维护性、扩展性和稳定性,是AI无法完全替代的核心能力。原型模式作为创建型模式的重要成员,专注于"通过复制现有对象来创建新对象",解决了复杂对象创建时效率低下、重复编码的问题,是高效创建对象的实用范式。

一、概念

原型模式(Prototype Pattern)是一种创建型设计模式,核心目标是用一个已经创建的实例(原型)作为模板,通过复制(克隆)这个原型来创建一个与原型相同或相似的新对象。简单来说,就是"复制粘贴"现有对象,无需重新执行复杂的创建逻辑,直接复用原型的属性和行为,同时可根据需求修改部分属性,实现快速创建。

比如软件中的"复制粘贴"功能、游戏中创建相同属性的角色、Spring中的Bean原型模式(每次获取都创建新实例,复用原型配置),本质上都是原型模式的应用。它避免了重复编写对象初始化代码,尤其适合创建过程复杂、属性繁多的对象。

二、核心思想

  1. 原型对象(Prototype):已经创建好的、可被复制的实例,实现克隆方法(用于返回自身的副本);
  2. 克隆方法(Clone) :原型对象的核心方法,分为浅克隆深克隆,负责创建并返回新的对象副本;
  3. 客户端(Client):无需关心对象的创建细节,只需调用原型对象的克隆方法,即可获取新的对象,按需修改属性。

原型模式的核心本质是复用原型、减少重复创建 ------通过克隆机制,跳过复杂的对象初始化流程,直接复用原型的结构和数据,既提高了对象创建效率,又保证了新对象与原型的一致性,同时支持灵活修改副本属性。

三、Java代码实现

以"游戏角色创建"场景为例:系统中存在战士、法师两种角色,每种角色都有姓名、等级、血量、技能等多个属性,创建角色的流程复杂(需初始化技能、设置初始属性)。用原型模式通过克隆原型角色,快速创建新角色,避免重复初始化。

1. 定义原型对象(游戏角色抽象类,实现克隆接口)

java 复制代码
/**
 * 原型对象:游戏角色抽象类
 * 实现Cloneable接口(标记可克隆),定义克隆方法和角色通用属性/行为
 */
public abstract class GameRole implements Cloneable {
    protected String name; // 角色名称
    protected int level; // 等级
    protected int blood; // 血量
    protected String skill; // 技能

    // 抽象方法:展示角色信息
    public abstract void showRoleInfo();

    // 克隆方法(核心),重写Object类的clone方法
    @Override
    protected GameRole clone() throws CloneNotSupportedException {
        // 浅克隆:直接复制基本数据类型,引用类型仅复制引用地址
        return (GameRole) super.clone();
    }

    // setter/getter方法(供客户端修改副本属性)
    public void setName(String name) {
        this.name = name;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public void setBlood(int blood) {
        this.blood = blood;
    }
}

2. 定义具体原型(战士角色+法师角色)

java 复制代码
/**
 * 具体原型1:战士角色
 * 继承原型抽象类,实现具体的角色行为,完成自身初始化
 */
public class Warrior extends GameRole {
    // 战士专属属性
    private String weapon; // 武器

    // 构造方法:初始化战士原型(复杂创建逻辑)
    public Warrior() {
        this.name = "战士原型";
        this.level = 1;
        this.blood = 1000;
        this.skill = "横扫千军";
        this.weapon = "长剑";
    }

    @Override
    public void showRoleInfo() {
        System.out.println("角色类型:战士");
        System.out.println("角色名称:" + name);
        System.out.println("等级:" + level);
        System.out.println("血量:" + blood);
        System.out.println("技能:" + skill);
        System.out.println("武器:" + weapon);
    }

    // 战士专属setter方法
    public void setWeapon(String weapon) {
        this.weapon = weapon;
    }
}

/**
 * 具体原型2:法师角色
 * 继承原型抽象类,实现具体的角色行为,完成自身初始化
 */
public class Mage extends GameRole {
    // 法师专属属性
    private String staff; // 法杖

    // 构造方法:初始化法师原型(复杂创建逻辑)
    public Mage() {
        this.name = "法师原型";
        this.level = 1;
        this.blood = 600;
        this.skill = "火球术";
        this.staff = "火焰法杖";
    }

    @Override
    public void showRoleInfo() {
        System.out.println("角色类型:法师");
        System.out.println("角色名称:" + name);
        System.out.println("等级:" + level);
        System.out.println("血量:" + blood);
        System.out.println("技能:" + skill);
        System.out.println("法杖:" + staff);
    }

    // 法师专属setter方法
    public void setStaff(String staff) {
        this.staff = staff;
    }
}

3. 浅克隆测试代码(默认克隆方式)

java 复制代码
/**
 * 客户端:游戏角色创建系统
 * 调用原型的克隆方法,快速创建新角色,修改副本属性
 */
public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 1. 创建战士原型
        GameRole warriorPrototype = new Warrior();
        System.out.println("=== 战士原型 ===");
        warriorPrototype.showRoleInfo();

        // 2. 克隆战士原型,创建新战士(修改名称、等级,复用其他属性)
        GameRole newWarrior = warriorPrototype.clone();
        newWarrior.setName("狂战士");
        newWarrior.setLevel(10);
        ((Warrior) newWarrior).setWeapon("巨斧"); // 强制转换,修改专属属性
        System.out.println("\n=== 克隆的新战士 ===");
        newWarrior.showRoleInfo();

        // 3. 创建法师原型
        GameRole magePrototype = new Mage();
        System.out.println("\n=== 法师原型 ===");
        magePrototype.showRoleInfo();

        // 4. 克隆法师原型,创建新法师
        GameRole newMage = magePrototype.clone();
        newMage.setName("冰法师");
        newMage.setLevel(8);
        ((Mage) newMage).setStaff("寒冰法杖");
        System.out.println("\n=== 克隆的新法师 ===");
        newMage.showRoleInfo();
    }
}

输出结果:

复制代码
=== 战士原型 ===
角色类型:战士
角色名称:战士原型
等级:1
血量:1000
技能:横扫千军
武器:长剑

=== 克隆的新战士 ===
角色类型:战士
角色名称:狂战士
等级:10
血量:1000
技能:横扫千军
武器:巨斧

=== 法师原型 ===
角色类型:法师
角色名称:法师原型
等级:1
血量:600
技能:火球术
法杖:火焰法杖

=== 克隆的新法师 ===
角色类型:法师
角色名称:冰法师
等级:8
血量:600
技能:火球术
法杖:寒冰法杖

4. 深克隆实现(解决浅克隆引用类型共享问题)

java 复制代码
/**
 * 新增:带引用类型属性的角色(测试深克隆)
 * 假设角色有"装备列表"(引用类型),浅克隆会导致副本与原型共享该列表
 */
public class Archer extends GameRole {
    // 引用类型属性:装备列表
    private List<String> equipment;

    // 构造方法:初始化弓箭手原型,初始化装备列表(复杂逻辑)
    public Archer() {
        this.name = "弓箭手原型";
        this.level = 1;
        this.blood = 800;
        this.skill = "箭雨";
        this.equipment = new ArrayList<>();
        equipment.add("木弓");
        equipment.add("皮甲");
        equipment.add("羽箭");
    }

    // 深克隆:重写clone方法,复制引用类型属性
    @Override
    protected GameRole clone() throws CloneNotSupportedException {
        // 1. 先执行浅克隆,获取基本类型的副本
        Archer cloneArcher = (Archer) super.clone();
        // 2. 复制引用类型属性(避免共享)
        cloneArcher.equipment = new ArrayList<>(this.equipment);
        return cloneArcher;
    }

    @Override
    public void showRoleInfo() {
        System.out.println("角色类型:弓箭手");
        System.out.println("角色名称:" + name);
        System.out.println("等级:" + level);
        System.out.println("血量:" + blood);
        System.out.println("技能:" + skill);
        System.out.println("装备:" + equipment);
    }

    // 新增装备(测试引用类型是否共享)
    public void addEquipment(String eq) {
        this.equipment.add(eq);
    }
}

// 深克隆测试代码
public class DeepCloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建弓箭手原型
        Archer archerPrototype = new Archer();
        System.out.println("=== 弓箭手原型(初始) ===");
        archerPrototype.showRoleInfo();

        // 克隆弓箭手,修改副本的装备列表
        Archer cloneArcher = (Archer) archerPrototype.clone();
        cloneArcher.setName("神射手");
        cloneArcher.addEquipment("精准箭袋"); // 给副本新增装备

        System.out.println("\n=== 弓箭手原型(克隆后) ===");
        archerPrototype.showRoleInfo(); // 原型装备列表不变
        System.out.println("\n=== 克隆的新弓箭手 ===");
        cloneArcher.showRoleInfo(); // 副本装备列表新增成功
    }
}

输出结果:

复制代码
=== 弓箭手原型(初始) ===
角色类型:弓箭手
角色名称:弓箭手原型
等级:1
血量:800
技能:箭雨
装备:[木弓, 皮甲, 羽箭]

=== 弓箭手原型(克隆后) ===
角色类型:弓箭手
角色名称:弓箭手原型
等级:1
血量:800
技能:箭雨
装备:[木弓, 皮甲, 羽箭]

=== 克隆的新弓箭手 ===
角色类型:弓箭手
角色名称:神射手
等级:1
血量:800
技能:箭雨
装备:[木弓, 皮甲, 羽箭, 精准箭袋]

5. 扩展:原型管理器(统一管理原型,简化克隆)

java 复制代码
/**
 * 原型管理器:统一管理所有原型对象,提供获取和克隆原型的方法
 * 适用于原型数量多、需要统一维护的场景
 */
public class PrototypeManager {
    // 存储原型对象(key:原型类型,value:原型实例)
    private static Map<String, GameRole> prototypeMap = new HashMap<>();

    // 初始化原型(项目启动时加载所有原型)
    static {
        prototypeMap.put("warrior", new Warrior());
        prototypeMap.put("mage", new Mage());
        prototypeMap.put("archer", new Archer());
    }

    // 私有构造(禁止实例化)
    private PrototypeManager() {}

    // 获取原型并克隆
    public static GameRole getCloneRole(String roleType) throws CloneNotSupportedException {
        GameRole prototype = prototypeMap.get(roleType);
        if (prototype == null) {
            throw new RuntimeException("不存在该类型的角色原型");
        }
        return prototype.clone();
    }
}

// 客户端使用原型管理器
public class ManagerClient {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 无需创建原型,直接通过管理器获取克隆对象
        GameRole warrior = PrototypeManager.getCloneRole("warrior");
        warrior.setName("战场先锋");
        System.out.println("=== 管理器克隆的战士 ===");
        warrior.showRoleInfo();

        GameRole mage = PrototypeManager.getCloneRole("mage");
        mage.setName("元素法师");
        System.out.println("\n=== 管理器克隆的法师 ===");
        mage.showRoleInfo();
    }
}

四、优缺点

1. 优点

  1. 提高对象创建效率:跳过复杂的初始化流程,通过克隆复用原型,尤其适合创建过程耗时、属性繁多的对象;
  2. 简化对象创建逻辑:客户端无需关心对象的创建细节,只需调用克隆方法,即可快速获取新对象;
  3. 灵活性高:克隆后可按需修改部分属性,既复用了原型的大部分属性,又能灵活定制新对象;
  4. 符合开闭原则:新增产品时,只需新增具体原型类,无需修改原有代码(如原型管理器可直接添加新原型)。

2. 缺点

  1. 克隆逻辑复杂:若对象包含多层引用类型属性(如集合、自定义对象),实现深克隆需递归复制所有引用对象,逻辑繁琐;
  2. 原型类需支持克隆:所有原型类必须实现Cloneable接口、重写clone方法,增加了代码侵入性;
  3. 不易维护:若原型对象的属性发生修改,所有克隆出来的对象都会受影响(若未重新克隆),维护成本较高。

五、应用场景

原型模式适用于对象创建复杂、需频繁创建相似对象、需复用对象属性的场景:

  1. 频繁创建相似对象:如游戏中批量创建相同类型的怪物、电商系统中批量创建相似的商品对象;
  2. 复杂对象创建:如对象包含多个属性、初始化流程复杂(如数据库查询、资源加载),克隆可避免重复执行这些流程;
  3. 框架中的应用:Spring框架中,Bean的scope为"prototype"(原型)时,每次获取Bean都会克隆原型Bean;Java中的ArrayList、HashMap等集合的clone方法,本质也是原型模式;
  4. 动态扩展场景:如通过原型管理器管理多个原型,客户端可动态选择克隆不同的原型,实现灵活扩展。

六、注意事项

  1. 区分浅克隆与深克隆:浅克隆仅复制基本数据类型和引用地址,引用类型属性会被原型和副本共享;深克隆会复制所有引用类型属性,原型与副本完全独立,需根据需求选择;
  2. 原型类需正确实现克隆:必须实现Cloneable接口(标记接口,无实际方法),并重写clone方法,否则会抛出CloneNotSupportedException异常;
  3. 避免克隆不可变对象:如String、Integer等不可变对象,克隆无意义(每次克隆都是同一个对象),无需使用原型模式;
  4. 结合单例模式:原型管理器通常设计为单例,避免重复创建管理器实例,统一维护原型对象。

总结

  1. 原型模式核心是通过克隆原型对象创建新对象,核心价值是复用原型、提高创建效率,简化复杂对象的创建逻辑;
  2. 核心区分浅克隆(仅复制基本类型)和深克隆(复制所有引用类型),实际开发中需根据对象结构选择合适的克隆方式;
  3. 优势是高效、灵活、简化创建,缺点是克隆逻辑复杂、有代码侵入性,适用于频繁创建相似复杂对象的场景;
  4. Spring的原型Bean、集合的clone方法,是原型模式的经典应用,理解其实现逻辑可快速上手实际开发。
相关推荐
helloworddm2 小时前
第一篇:设计模式在 Android 视频播放器中的实战应用
android·设计模式·音视频
砍光二叉树3 小时前
【设计模式】创建型-建造者模式
设计模式·建造者模式
RFCEO1 天前
JavaScript基础课程十四、原型与原型链(JS 核心底层)
开发语言·原型模式·prototype原型详解·javascript基础课·构造函数原型方法定义与使用·js原型链继承机制入门·t原型链顶层null原理
szm02251 天前
设计模式-
设计模式
砍光二叉树1 天前
【设计模式】创建型-抽象工厂模式
设计模式·抽象工厂模式
砍光二叉树1 天前
【设计模式】创建型-工厂方法模式
设计模式·工厂方法模式
我爱学习_zwj1 天前
设计模式-2(单例模式与原型模式)
前端·javascript·设计模式
砍光二叉树1 天前
【设计模式】创建型-单例模式
单例模式·设计模式
我爱学习_zwj1 天前
设计模式-3(装饰器模式)
前端·设计模式·装饰器模式