23种设计模式——原型模式

本文详细解读了原型模式的工作原理,介绍了其优点与缺点,并展示了浅拷贝和深拷贝的实现方法。通过实例演示,学习如何在Java中利用原型模式创建高效对象副本,包括Object的浅拷贝和自定义类的深拷贝技术。

23种设计模式——原型模式

1、原型模式概述

原型模式介绍

1、原型模式(Prototype模式)是指:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。

2、原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节,因此用这种方式创建对象非常高效。

3、工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即对象.clone()

4、形象的理解:孙大圣拔出猴毛,变出其它孙大圣

原型模式优缺点

原型模式的优点:

  • Java自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
  • 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

原型模式的缺点:

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

2、原型模式的结构图

原型模式的结构

原型模式包含以下主要角色。

  1. 原型类 Prototype:声明一个克隆自己的接口。
  2. 具体原型类 Realizetype:实现原型类的 clone() 方法,实现克隆自己的操作。它是可被复制的对象,可以有多个。
  3. 访问类 PrototypeTes:使用具体原型类中的 clone() 方法来复制新的对象。

原型模式的结构图

在这里插入图片描述

3、原型模式的实现

3.1、浅拷贝和深拷贝

浅拷贝介绍

对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。

对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

浅拷贝是使用默认的clone()方法来实现。

深拷贝介绍

深拷贝会复制对象的所有基本数据类型的成员变量值。

深拷贝为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象进行拷贝。

深拷贝实现方式1:重写clone方法来实现深拷贝,

深拷贝实现方式2:通过对象序列化实现深拷贝。(推荐使用)

3.2、实现浅拷贝

Java 中的 Object 类提供了浅拷贝的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的浅拷贝,这里的 Cloneable 接口就是原型类。

具体原型类:

package com.cheng.prototype;

public class Sheep implements Cloneable{

    private String name;
    private int age;
    private String color;


    public Sheep() {
    }

    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }

    //重写clone方法
    @Override
    protected Object clone() {
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return sheep;
    }
}

访问类测试:使用具体原型类中的 clone() 方法来复制新的对象

package com.cheng.prototype;

public class PrototypeTes {
    public static void main(String[] args) {
        Sheep sheep1 = new Sheep("wanli", 1, "白色");

        //原型模式完成对象创建
        Sheep sheep2 = (Sheep) sheep1.clone();
        Sheep sheep3 = (Sheep) sheep1.clone();
        Sheep sheep4 = (Sheep) sheep1.clone();
        Sheep sheep5 = (Sheep) sheep1.clone();
        Sheep sheep6 = (Sheep) sheep1.clone();

        System.out.println(sheep2);
        System.out.println(sheep3);
        System.out.println(sheep4);
        System.out.println(sheep5);
        System.out.println(sheep6);
    }
}

运行访问类,进行测试:

在这里插入图片描述

这样程序具有更高的效率和扩展性!

3.2、实现深拷贝

创建引用类型类:

package com.cheng.prototype.demo02;

import java.io.Serializable;

public class DeepCloneableTarget implements Serializable,Cloneable {

    private static final long serialVersionUID = 1L;

    private String cloneName;
    private String cloneClass;

    public DeepCloneableTarget(String cloneName,String cloneClass){
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }
    
    @Override
    public String toString() {
        return "DeepCloneableTarget{" +
                "cloneName='" + cloneName + '\'' +
                ", cloneClass='" + cloneClass + '\'' +
                '}';
    }
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

创建具体原型类:

package com.cheng.prototype.demo02;

import java.io.*;

public class DeepProtoType implements Serializable,Cloneable {

    public String name;
    public DeepCloneableTarget deepCloneableTarget;


    public DeepProtoType(){

    }

    @Override
    public String toString() {
        return "DeepProtoType{" +
                "name='" + name + '\'' +
                ", deepCloneableTarget=" + deepCloneableTarget +
                '}';
    }

    //深拷贝实现方式1:重写clone方法来实现深拷贝,
    @Override
    protected Object clone() {
        Object deep = null;
        DeepProtoType deepProtoType = null;
        //先对DeepProtoType的基本数据类型和String类型的属性进行拷贝
        try {
            deep = super.clone();
            //然后对引用类型DeepCloneableTarget的属性进行拷贝
            deepProtoType = (DeepProtoType) deep;
            deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return deepProtoType;
    }

    //深拷贝实现方式2:通过对象序列化实现深拷贝。(推荐使用),
    //这种方式把对象当做一个整体进行克隆,不像方式一一样,引用对象要单独拿出来克隆
    public DeepProtoType deepClone() {

        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;

        try {
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);//把对象序列化

            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            DeepProtoType deepType = (DeepProtoType) ois.readObject();//把对象反序列化
            return deepType;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }finally {
            try {
                if (ois != null)
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (bis != null)
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (oos != null)
                    oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (bos != null)
                    bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

访问类测试:

package com.cheng.prototype.demo02;

public class Client {
    public static void main(String[] args) {
        DeepProtoType t = new DeepProtoType();

        t.name = "神明";
        t.deepCloneableTarget = new DeepCloneableTarget("万里","万里");

        //测试 深拷贝实现方式1:重写clone方法来实现深拷贝,
        DeepProtoType clone1 = (DeepProtoType)t.clone();
        System.out.println("测试 深拷贝实现方式1:重写clone方法来实现深拷贝");
        //打印原型对象和原型对象中引用对象的hashCode
        System.out.println(t +","+ t.deepCloneableTarget.hashCode());
        //打印克隆对象和克隆对象中引用对象的hashCode
        System.out.println(clone1 +","+ clone1.deepCloneableTarget.hashCode());

        System.out.println();

        //测试 深拷贝实现方式2:通过对象序列化实现深拷贝。(推荐使用)
        DeepProtoType deepClone = t.deepClone();
        System.out.println("测试 深拷贝实现方式2:通过对象序列化实现深拷贝。(推荐使用)");
        //打印原型对象和原型对象中引用对象的hashCode
        System.out.println(t +","+ t.deepCloneableTarget.hashCode());
        //打印克隆对象和克隆对象中引用对象的hashCode
        System.out.println(deepClone +","+ deepClone.deepCloneableTarget.hashCode());

    }
}

运行访问类,进行测试:

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万里顾—程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值