原型设计模式

简介

原型模式(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());
    }
}

总结

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

相关推荐
long_mingyue6 天前
JavaScript 对象操作、继承与模块化实现
javascript·原型模式·xss
x_SpiderMan6 天前
XSS原型与原型链
前端·原型模式·xss
淦暴尼9 天前
认识ETL流程:数据工程的基石
数据仓库·etl·原型模式
晓131310 天前
JavaScript进阶篇——第八章 原型链、深浅拷贝与原型继承全解析
开发语言·javascript·原型模式
Honesty86102410 天前
深入排查:@Scope(“prototype“)与@RequestScope字段篡改问题全链路分析
java·spring boot·spring·原型模式
Honesty86102410 天前
Spring 作用域冲突深度解析:@Scope(“prototype“)与@RequestScope的冲突与解决方案
java·spring·原型模式
前端橙一陈10 天前
原型继承(prototypal inheritance)的工作原理
开发语言·javascript·原型模式
极光雨雨13 天前
【设计模式】原型模式 原型管理器
设计模式·原型模式
vvilkim13 天前
深入理解设计模式:原型模式(Prototype Pattern)
java·设计模式·原型模式
灰海17 天前
原型与原型链到底是什么?
开发语言·前端·javascript·es6·原型模式·原生js