原型设计模式

简介

原型模式(Prototype Pattern)指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象,属于创建型设计模式。

应用场景

(1)创建对象成本较大(例如,初始化时间长,占用CPU太多,或者占用网络资源太多等),需要优化资源。

(2)创建一个对象需要烦琐的数据准备或访问权限等,需要提高性能或者提高安全性。

(3)系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值。

在Spring中,原型模式应用得非常广泛,例如scope="prototype"、JSON.parseObject(),都是原型模式的具体应用。

优点

(1)Java自带的原型模式基于内存二进制流的复制,在性能上比直接new一个对象更加优良。

(2)可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

缺点

(1)需要为每一个类都配置一个clone方法。

(2)clone方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。 (3)当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。

通用模板

  1. 创建原型接口:规定复制接口。

    java 复制代码
    // 抽象原型
    public interface IPrototype<T> {
        T clone();
    }
  2. 具体原型类:被复制的对象。

    java 复制代码
    public class Prototype implements IPrototype<Prototype> {
        private String desc;
    
        public Prototype(String desc) {
            this.desc = desc;
        }
    
        public Prototype clone() {
            // 进行复制
            return new Prototype(desc);
        }
    
    
        @Override
        public String toString() {
            return "Prototype{" +
                    "desc='" + desc + '\'' +
                    '}';
        }
    }

模板测试

  1. 代码

    java 复制代码
    public class Client {
        public static void main(String[] args) {
            // 创建原型对象
            Prototype prototypeA = new Prototype("PrototypeA");
            System.out.println(prototypeA);
            // 复制原型对象
            Prototype clone = prototypeA.clone();
            System.out.println(clone);
        }
    }
  2. 结果

    text 复制代码
    Prototype{desc='PrototypeA'}
    Prototype{desc='PrototypeA'}

Java Object clone方法

Java的Object提供了一个clone()方法,它的意图就是复制一个新的对象出来,我们需要实现一个Cloneable接口来标识一个对象是"可复制"的:

  1. 原型模型写法

    java 复制代码
    public class Student implements Cloneable {
        private int id;
        private String name;
        private int score;
    
        // 复制新对象并返回:
        public Object clone() {
            Student std = new Student();
            std.id = this.id;
            std.name = this.name;
            std.score = this.score;
            return std;
        }
    }
  2. 测试

    java 复制代码
    public class Client {
        public static void main(String[] args) {
            Student std1 = new Student();
            std1.setId(123);
            std1.setName("Bob");
            std1.setScore(88);
            // 复制新对象:
            Student std2 = (Student) std1.clone();
            System.out.println(std1);
            System.out.println(std2);
            System.out.println(std1 == std2); // false
        }
    }
  3. 结果

    text 复制代码
    com.demo.Student@7f31245a
    com.demo.Student@6d6f6e28
    false

"生搬硬套"实战

场景描述

假设我们有一个游戏场景,游戏中有很多不同类型的怪物(Monster),我们需要不断创建怪物对象来填充游戏世界。每个怪物都有自己的属性,比如生命值(health)、攻击力(attack)等。如果我们每次都通过构造函数来创建一个新的怪物实例并设置其属性,那么这将非常耗时且代码会变得冗长。这时,原型模式就可以派上用场了。

代码开发
java 复制代码
public class Monster implements Cloneable {
    private int health;
    private int attack;

    public Monster(int health, int attack) {
        this.health = health;
        this.attack = attack;
    }

    // 获取健康值
    public int getHealth() {
        return health;
    }

    // 设置健康值
    public void setHealth(int health) {
        this.health = health;
    }

    // 获取攻击力
    public int getAttack() {
        return attack;
    }

    // 设置攻击力
    public void setAttack(int attack) {
        this.attack = attack;
    }

    // 实现克隆方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
  1. 测试
java 复制代码
public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建一个原型怪物
        Monster prototypeMonster = new Monster(100, 50);

        // 使用原型模式克隆出多个怪物
        Monster monster1 = (Monster) prototypeMonster.clone();
        Monster monster2 = (Monster) prototypeMonster.clone();

        // 修改每个怪物的特性
        monster1.setHealth(90);
        monster2.setAttack(60);

        System.out.println("Monster 1: Health=" + monster1.getHealth() + ", Attack=" + monster1.getAttack());
        System.out.println("Monster 2: Health=" + monster2.getHealth() + ", Attack=" + monster2.getAttack());
    }
}

总结

原型模式的核心在于复制原型对象。以系统中已存在的一个对象为原型,直接基于内存二进制流进行复制,不需要再经历耗时的对象初始化过程(不调用构造函数),性能提升许多。当对象的构建过程比较耗时时,可以把当前系统中已存在的对象作为原型,对其进行复制(一般是基于二进制流的复制),躲避初始化过程,使得新对象的创建时间大大缩短。

相关推荐
希冀1232 天前
【JavaScript】Javascript—JS进阶—Day03
开发语言·javascript·原型模式
想吃火锅100521 天前
【前端手撕】instanceof
前端·javascript·原型模式
UXbot21 天前
帮助企业低门槛开展AI应用开发的平台推荐
前端·低代码·ui·交互·产品经理·原型模式·web app
UXbot21 天前
如何选择适合公司项目的UI设计工具?企业选型指南
前端·低代码·ui·团队开发·原型模式·设计规范·web app
UXbot22 天前
原型设计工具如何帮助新人快速进入产品行业?
前端·低代码·ui·交互·团队开发·原型模式·web app
sunny.day1 个月前
js原型与原型链
开发语言·javascript·原型模式·js原型链
UXbot1 个月前
AI网页开发工具能替代工具吗?5大平台对比
前端·人工智能·低代码·ui·原型模式·web app
weixin_307779131 个月前
从“大海捞针”到“主动推理”:AI如何重塑云原生故障诊断的根因链
开发语言·人工智能·算法·自动化·原型模式
swordbob1 个月前
prototype 注入到 singleton 里,prototype是否还是线程安全的
安全·spring·单例模式·原型模式
isNotNullX1 个月前
企业数据中台建设,ETL工具选错了会踩哪些坑?
数据仓库·etl·原型模式