原型设计模式

原型模式(Prototype Pattern)是一种创建型设计模式,其主要目的是通过复制(克隆)现有对象来创建新对象,而无需显式地使用构造函数创建新对象。这种模式通常用于创建成本较高或复杂的对象,以避免重复的初始化工作。

结构

  1. 原型接口(Prototype Interface) :通常需要创建一个原型接口,该接口定义了一个clone方法,用于复制对象。所有需要支持克隆操作的类都需要实现这个接口。
  2. 具体原型(Concrete Prototype) :具体原型类是实现了原型接口的类,它实际上进行对象的复制操作。具体原型类需要实现clone方法来克隆自身。
  3. 客户端(Client):客户端代码通过原型接口来请求克隆操作(即使用具体原型类中的clone()方法来复制新对象),而不需要知道具体的对象创建细节。

实现

原型模式可以分为浅克隆深克隆两种形式,取决于复制的方式。

  • 浅克隆:创建一个新对象,新对象的属性与原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有的对象地址。

Java中的Object类中提供了clone()方法来实现浅克隆。

java 复制代码
class Prototype implements Cloneable{
    public Prototype() {
        System.out.println("创建具体的原型对象");
    }

    @Override
    protected Prototype  clone() throws CloneNotSupportedException {
        System.out.println("复制成功!");
        return (Prototype) super.clone();
    }
}

public class PrototypeDemo {
    public static void main(String[] args) throws CloneNotSupportedException{
        Prototype original = new Prototype();

        Prototype clone = original.clone();

        System.out.println(original == clone); //false
    }
}

上面的方法很简单,当然,还有另外一种方法,就是自己创建原型接口,按照上面的原型模式的结构来实现

java 复制代码
// 原型接口
interface Prototype {
    Prototype clone();
}

// 具体原型类
class ConcretePrototype implements Prototype {
    private String data;

    public ConcretePrototype(String data) {
        this.data = data;
    }

    @Override
    public Prototype clone() {
        return new ConcretePrototype(this.data);
    }

    public String getData() {
        return data;
    }
}

public class PrototypeDemo {
    public static void main(String[] args) {
        // 创建一个具体原型对象
        Prototype original = new ConcretePrototype("Hello, world!");

        // 克隆原型对象来创建新对象
        Prototype clone = original.clone();

        // 输出原型和克隆对象的数据
        System.out.println("Original Data: " + ((ConcretePrototype) original).getData());
        System.out.println("Clone Data: " + ((ConcretePrototype) clone).getData());
    }
}

使用场景

原型模式使用场景有:

  1. 对象的创建成本较高:如果创建一个对象的成本很高,例如需要从数据库中加载大量数据或进行复杂的计算,那么使用原型模式可以避免多次创建相同的对象,而是通过克隆已有对象来创建新对象,从而提高性能。

  2. 对象的创建过程复杂:当对象的创建过程非常复杂,包括多个步骤或依赖于其他对象时,使用原型模式可以简化代码,因为您只需克隆一个已有对象,而不必重复执行复杂的创建步骤。

  3. 需要保持对象的不变性:有些对象需要保持不变性,即不能通过直接赋值属性的方式修改其状态。原型模式可以帮助您创建对象的副本,而不会影响原始对象的状态。

  4. 大量相似对象的创建:当需要创建大量相似但略有差异的对象时,原型模式非常有用。您可以创建一个原型对象,然后根据需要克隆该对象并进行适当的修改。

  5. 支持动态配置对象:原型模式允许您在运行时动态配置对象,通过克隆已有对象并进行修改,而不必硬编码不同的配置选项。

  6. 减少子类的创建:在某些情况下,如果您有多个子类,而这些子类只有一些差异,可以使用原型模式来创建这些子类的实例,而不必为每个子类都创建一个独立的类。

深克隆

在实现深克隆时,有几种常见的方式:

  1. 手动实现深克隆:这是最基本的方式,开发人员需要手动编写代码来遍历原始对象的属性和子对象,并创建相应的新对象来存储复制后的数据。这通常涉及递归操作,以确保所有嵌套对象也被深克隆。
java 复制代码
class Address implements Cloneable {
    private String street;
    private String city;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public Address(String street, String city) {
        this.street = street;
        this.city = city;
    }

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

class Person implements Cloneable {
    public String getName() {
        return name;
    }

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

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    private String name;
    private Address address;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person clonedPerson = (Person) super.clone();
        clonedPerson.address = (Address) address.clone();
        return clonedPerson;
    }
}

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("步行街", "北京");
        Person originalPerson = new Person("Alice", address);

        Person clonedPerson = (Person) originalPerson.clone();

        System.out.println(originalPerson.getName()+"   "+originalPerson.getAddress().getStreet()); // Alice   步行街
        clonedPerson.setName("Bob");
        clonedPerson.getAddress().setStreet("人民公园");
        System.out.println(clonedPerson.getName()+"   "+clonedPerson.getAddress().getStreet());   // Bob   人民公园
    }
}
  1. 使用序列化和反序列化:这种方式需要将原始对象序列化为一个字节流,然后再将其反序列化为新对象。这可以通过语言内置的序列化机制或第三方库来实现。在这个过程中,对象的所有属性和嵌套对象都会被复制。
java 复制代码
import java.io.*;

class Address implements Serializable {
    private String street;
    private String city;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public Address(String street, String city) {
        this.street = street;
        this.city = city;
    }

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

class Person implements Serializable  {
    public String getName() {
        return name;
    }

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

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    private String name;
    private Address address;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person clonedPerson = (Person) super.clone();
        clonedPerson.address = (Address) address.clone();
        return clonedPerson;
    }
}

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Address address = new Address("步行街", "北京");
        Person originalPerson = new Person("Alice", address);

        // 序列化主类
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(originalPerson);

        // 反序列化创造克隆类
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Person clonedPerson = (Person) ois.readObject();

        System.out.println(originalPerson.getName()+"   "+originalPerson.getAddress().getStreet()); // Alice   步行街
        clonedPerson.setName("Bob");
        clonedPerson.getAddress().setStreet("人民公园");
        System.out.println(clonedPerson.getName()+"   "+clonedPerson.getAddress().getStreet());   // Bob   人民公园
    }
}
相关推荐
xiaolin03339 分钟前
【设计模式】- 行为型模式1
设计模式·状态模式·责任链模式·策略模式·命令模式·模板方法模式·行为型模式
沐土Arvin1 小时前
深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
开发语言·前端·javascript·设计模式·html
bao_lanlan2 小时前
兰亭妙微:用系统化思维重构智能座舱 UI 体验
ui·设计模式·信息可视化·人机交互·交互·ux·外观模式
总是难免3 小时前
设计模式 - 单例模式 - Tips
java·单例模式·设计模式
菥菥爱嘻嘻4 小时前
JS手写代码篇---手写 new 操作符
开发语言·javascript·原型模式
Java致死8 小时前
设计模式Java
java·开发语言·设计模式
ghost14320 小时前
C#学习第23天:面向对象设计模式
开发语言·学习·设计模式·c#
敲代码的 蜡笔小新1 天前
【行为型之迭代器模式】游戏开发实战——Unity高效集合遍历与场景管理的架构精髓
unity·设计模式·c#·迭代器模式
敲代码的 蜡笔小新2 天前
【行为型之命令模式】游戏开发实战——Unity可撤销系统与高级输入管理的架构秘钥
unity·设计模式·架构·命令模式
m0_555762902 天前
D-Pointer(Pimpl)设计模式(指向实现的指针)
设计模式