23种设计模式之原型模式

目录

  • [1. 简介](#1. 简介)
  • [2. 实现](#2. 实现)
    • [2.1 原来的方式(使用newg关键字)](#2.1 原来的方式(使用newg关键字))
    • [2.2 使用接口Cloneable](#2.2 使用接口Cloneable)
    • [2.3 浅拷贝与深拷贝(拓展)](#2.3 浅拷贝与深拷贝(拓展))
  • [3. 总结](#3. 总结)

1. 简介

原型模式 (Prototype Pattern)是一种创建型设计模式。它的主要思想是通过复制一个已经存在的对象(原型)来创建新的对象,而不是使用传统的通过构造函数来创建对象的方式。这种模式的好处是可以在运行时动态地创建对象,并且可以根据需要灵活地修改复制后的对象。

例如,在一个游戏中,可能有多种类型的怪物。当需要生成新的怪物时,不是每次都从无到有地创建,而是复制一个已有的怪物原型,然后根据具体情况(如等级、属性加成等)进行修改,这样可以提高效率。

在 Java 中,实现原型模式通常需要让原型类实现java.lang.Cloneable接口。这个接口是一个标记接口,它没有任何方法,只是用来表明这个类的对象是可以被克隆的。

然后,在原型类中重写Object类的clone()方法。clone()方法是Object类提供的一个受保护的方法,用于创建并返回对象的一个副本。

2. 实现

2.1 原来的方式(使用newg关键字)

Pig.java

java 复制代码
public class Pig {
    private String name;
    private String doSomeThing;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDoSomeThing() {
        return doSomeThing;
    }

    public void setDoSomeThing(String doSomeThing) {
        this.doSomeThing = doSomeThing;
    }

    @Override
    public String toString() {
        return "Pig{" +
                "name='" + name + '\'' +
                ", doSomeThing='" + doSomeThing + '\'' +
                "} , " + super.toString();
    }
}

Test.java

java 复制代码
public class Test {
    public static void main(String[] args) {
        Pig pig = new Pig();
        pig.setName("小猪佩奇");
        pig.setDoSomeThing("吃饭");
        System.out.println(pig);

        Pig pig2 = new Pig();
        pig2.setName("小猪乔治");
        pig2.setDoSomeThing("吃米");
        System.out.println(pig2);

        Pig pig3 = new Pig();
        pig2.setName("大猪");
        pig2.setDoSomeThing("睡觉");
        System.out.println(pig2);
    }
}

输出结果:

Pig{name='小猪佩奇', doSomeThing='吃饭'} , yxz.prototype.Pig@1b6d3586
Pig{name='小猪乔治', doSomeThing='吃米'} , yxz.prototype.Pig@4554617c
Pig{name='大猪', doSomeThing='睡觉'} , yxz.prototype.Pig@4554617c

2.2 使用接口Cloneable

Pig.java

java 复制代码
package yxz.prototype;


public class Pig implements Cloneable{
    public Pig(){
        System.out.println("小猪初始化。。。");
    }

    private String name;
    private String doSomeThing;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDoSomeThing() {
        return doSomeThing;
    }

    public void setDoSomeThing(String doSomeThing) {
        this.doSomeThing = doSomeThing;
    }

    @Override
    public String toString() {
        return "Pig{" +
                "name='" + name + '\'' +
                ", doSomeThing='" + doSomeThing + '\'' +
                "} , " + super.toString();
    }

}

Test.java

java 复制代码
package yxz.prototype;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Pig pig = new Pig();
        pig.setName("小猪佩奇");
        pig.setDoSomeThing("吃饭");
        System.out.println(pig);

        Pig pig2 = new Pig();
        pig2.setName("小猪乔治");
        pig2.setDoSomeThing("吃米");
        System.out.println(pig2);

        Pig pig3 = new Pig();
        pig2.setName("大猪");
        pig2.setDoSomeThing("睡觉");
        System.out.println(pig2);

        // 使用原型设计模式
        Pig peiqi = new Pig();
        peiqi.setName("小猪佩奇");
        peiqi.setDoSomeThing("吃饭");
        System.out.println(peiqi);

        Pig george = (Pig)peiqi.clone();
        george.setName("小猪乔治");
        george.setDoSomeThing("吃米");
        System.out.println(george);

    }
}

运行结果:

小猪初始化。。。
Pig{name='小猪佩奇', doSomeThing='吃饭'} , yxz.prototype.Pig@1b6d3586
小猪初始化。。。
Pig{name='小猪乔治', doSomeThing='吃米'} , yxz.prototype.Pig@4554617c
小猪初始化。。。
Pig{name='大猪', doSomeThing='睡觉'} , yxz.prototype.Pig@4554617c
小猪初始化。。。
Pig{name='小猪佩奇', doSomeThing='吃饭'} , yxz.prototype.Pig@74a14482
Pig{name='小猪乔治', doSomeThing='吃米'} , yxz.prototype.Pig@1540e19d

2.3 浅拷贝与深拷贝(拓展)

浅拷贝 :在上面的示例中,clone()方法实现的是浅拷贝。浅拷贝会创建一个新的对象,新对象的基本数据类型的属性会被复制,但是如果属性是引用类型,那么只是复制了引用,而不是复制引用指向的对象。例如,如果Prototype类中有一个引用类型的属性AnotherClass anotherObject,在浅拷贝后,新对象和原对象的anotherObject属性将指向同一个对象。

深拷贝:深拷贝会创建一个新的对象,并且会递归地复制对象的所有属性,包括引用类型的属性所指向的对象。这样,原始对象和克隆后的对象完全独立,修改其中一个不会影响另一个。

深拷贝的方式:

java 复制代码
class MyClass implements Cloneable {
    private String field1;
    private NestedClass nestedObject;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        MyClass cloned = (MyClass) super.clone();
        cloned.nestedObject = (NestedClass) nestedObject.clone(); // 深拷贝内部的引用对象
        return cloned;
    }
}

可以看到,深拷贝是新创建了一个对象。

3. 总结

  • 应用场景
    • 对象的创建成本较高时:如果对象的创建过程涉及到复杂的初始化操作,如读取配置文件、建立数据库连接等,使用原型模式可以避免重复这些操作。通过复制已经初始化好的原型对象,可以快速地创建新的对象。
    • 动态配置对象时:在需要根据运行时的情况动态地生成对象的场景中,原型模式很有用。例如,在图形编辑软件中,用户可以复制已有的图形对象(如圆形、矩形等),然后根据自己的需求修改复制后的图形的属性,如大小、颜色等。
相关推荐
百度智能云技术站1 小时前
百度百舸万卡集群的训练稳定性系统设计和实践
设计模式
Seven972 小时前
【设计模式】享元模式教你如何分离内部与外部状态
java·后端·设计模式
Seven973 小时前
【设计模式】利用组合模式带你走进树形结构的世界
java·后端·设计模式
Seven973 小时前
【设计模式】掌握算法骨架:利用模板方法模式实现代码复用
java·后端·设计模式
Seven973 小时前
【设计模式】从智能音箱到软件设计:探索外观模式的实际应用案例
java·后端·设计模式
Seven973 小时前
【设计模式】如何通过桥接模式解决系统扩展难题?
java·后端·设计模式
Seven973 小时前
【设计模式】告别继承噩梦:用装饰者模式简化代码结构
java·后端·设计模式
Seven974 小时前
【设计模式】如何使用适配器模式让不兼容的类协同工作?
java·后端·设计模式
香菇滑稽之谈4 小时前
装饰器模式的C++实现示例
c++·算法·设计模式·装饰器模式
牵牛老人4 小时前
C++设计模式-简单工厂模式:从原理、应用、实践指南与常见问题和解决方案深度解析
c++·设计模式·简单工厂模式