设计模式-原型模式

文章目录

1.传统方式解决克隆羊问题

1.问题描述
2.类图
3.目录结构
4.代码实现
1.Sheep.java
java 复制代码
package com.sun.tradition;

/**
 * Description:
 * @Author sun
 * @Create 2024/5/28 19:26
 * @Version 1.0
 */
public class Sheep {
    private String name;
    private int age;
    private String color;

    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 + '\'' +
                '}';
    }
}
2.Client.java
java 复制代码
package com.sun.tradition;

/**
 * Description: 使用传统的方式复制十只羊
 * @Author sun
 * @Create 2024/5/28 19:26
 * @Version 1.0
 */
public class Client {
    public static void main(String[] args) {
        Sheep sheep = new Sheep("tom", 1, "白色");
        Sheep sheep1 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep6 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep7 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep8 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep9 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        System.out.println(sheep);
    }
}
5.优缺点分析

2.原型模式解决克隆羊问题(浅拷贝)

1.基本介绍
2.类图
3.目录结构
4.代码实现
1.Sheep.java 实现Cloneable接口的clone方法,使用原型模式来实现克隆
java 复制代码
package com.sun.improve;

/**
 * Description: 实现Cloneable接口的clone方法,使用原型模式来实现克隆
 * @Author sun
 * @Create 2024/5/28 19:26
 * @Version 1.0
 */
public class Sheep implements Cloneable{
    private String name;
    private int age;
    private String color;

    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 + '\'' +
                '}';
    }

    @Override
    protected Sheep clone() throws CloneNotSupportedException {
        return (Sheep) super.clone();
    }
}
2.Client.java
java 复制代码
package com.sun.improve;

/**
 * Description: 原型模式的客户端
 * @Author sun
 * @Create 2024/5/28 19:43
 * @Version 1.0
 */
public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep sheep = new Sheep("tom", 1, "白色");
        Sheep clone = sheep.clone();
        Sheep clon2 = sheep.clone();
        Sheep clon3 = sheep.clone();
        Sheep clon4 = sheep.clone();
        System.out.println(clone);
    }
}

3.原型模式在Spring框架中的源码分析

1.基本介绍
2.解释
  • 在Spring中配置一个bean的时候,有一个scope属性可以选择配置prototype(原型模式)
  • 当配置了这个参数,每次getBean的时候就相当于使用原型模式创建了一个新的对象,然后将原对象的属性浅拷贝到这个新的对象

4.深拷贝

1.默认的原型模式为浅拷贝
1.在Sheep.java中添加一个引用类型的数组
2.在Client.java测试克隆的羊和原来的羊的属性是不是一个数组
3.结果表明,默认的原型模式克隆出来的对象,会将引用类型的属性指向原型的属性,共享内存空间,也就是浅拷贝
2.浅拷贝与深拷贝
1.浅拷贝
2.深拷贝

5.实现深拷贝的两种方式

1.重写clone方法实现深拷贝
1.DeepCloneableTarget.java
java 复制代码
package com.sun.deepcopy01;

import java.io.Serializable;

/**
 * Description: 要被深拷贝的对象,内部含有引用类型
 * @Author sun
 * @Create 2024/5/28 20:20
 * @Version 1.0
 */
public class DeepCloneableTarget implements Serializable, Cloneable {
    public static final long serialVersionUID = 1L;

    private String name;

    private int[] arr; // 引用类型需要手动拷贝一份

    public DeepCloneableTarget(String name, int[] arr) {
        this.name = name;
        this.arr = arr;
    }

    /**
     * 重写克隆方法,使当前对象可以完成深拷贝
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected DeepCloneableTarget clone() throws CloneNotSupportedException {
        // 首先调用一次父类的克隆方法,浅拷贝一份当前对象
        DeepCloneableTarget clone = (DeepCloneableTarget) super.clone();
        // 目前的clone对象的arr是浅拷贝,所以需要将其手动拷贝一份
        int[] copyArr = new int[arr.length];
        if (arr != null) {
            int j = 0;
            for (int i : arr) {
                copyArr[j ++] = i;
            }
        }
        // 重新设置一下拷贝后的数组
        clone.arr = copyArr;
        return clone;
    }

    public int[] getArr() {
        return arr;
    }
}
2.Client.java
java 复制代码
package com.sun.deepcopy01;


import java.util.Arrays;

/**
 * Description: 原型模式的客户端
 * @Author sun
 * @Create 2024/5/28 19:43
 * @Version 1.0
 */
public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        DeepCloneableTarget deepCloneableTarget = new DeepCloneableTarget("sunxiansheng", new int[]{1, 2, 3});
        DeepCloneableTarget clone = deepCloneableTarget.clone();
        // 测试深拷贝
        System.out.println(deepCloneableTarget.getArr() == clone.getArr());
        System.out.println(Arrays.toString(deepCloneableTarget.getArr()));
        System.out.println(Arrays.toString(clone.getArr()));
    }
}
3.结果
2.对象序列化实现深拷贝(推荐)
1.DeepCloneableTarget.java
java 复制代码
package com.sun.deepcopy02;

import java.io.*;

/**
 * Description: 要被深拷贝的对象,内部含有引用类型
 * @Author sun
 * @Create 2024/5/28 20:20
 * @Version 1.0
 */
public class DeepCloneableTarget implements Serializable, Cloneable {

    public static final long serialVersionUID = 1L;

    private String name;

    private int[] arr;

    public DeepCloneableTarget(String name, int[] arr) {
        this.name = name;
        this.arr = arr;
    }

    public int[] getArr() {
        return arr;
    }

    // 通过对象的序列化实现深拷贝
    public DeepCloneableTarget deepClone() {

        // 创建流对象
        ByteArrayOutputStream byteArrayOutputStream = null;
        ObjectOutputStream objectOutputStream = null;
        ByteArrayInputStream byteArrayInputStream = null;
        ObjectInputStream objectInputStream = null;

        try {
            // 序列化
            byteArrayOutputStream = new ByteArrayOutputStream();
            // 将字节数组输出流转换为对象输出流
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            // 将当前的对象以对象流的方式输出
            objectOutputStream.writeObject(this);

            // 反序列化
            byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            DeepCloneableTarget copyObject = (DeepCloneableTarget) objectInputStream.readObject();

            return copyObject;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            // 关闭流
            try {
                if (byteArrayOutputStream != null) {
                    byteArrayOutputStream.close();
                }
                if (objectOutputStream != null) {
                    objectOutputStream.close();
                }
                if (byteArrayInputStream != null) {
                    byteArrayInputStream.close();
                }
                if (objectInputStream != null) {
                    objectInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}
2.Client.java
java 复制代码
package com.sun.deepcopy02;


import java.util.Arrays;

/**
 * Description: 原型模式的客户端
 * @Author sun
 * @Create 2024/5/28 19:43
 * @Version 1.0
 */
public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        DeepCloneableTarget deepCloneableTarget = new DeepCloneableTarget("sunxiansheng", new int[]{1, 2, 3});
        DeepCloneableTarget clone = deepCloneableTarget.deepClone();
        // 测试深拷贝
        System.out.println(deepCloneableTarget.getArr() == clone.getArr());
        System.out.println(Arrays.toString(deepCloneableTarget.getArr()));
        System.out.println(Arrays.toString(clone.getArr()));
    }
}
3.结果
3.原型模式的注意事项
相关推荐
魔道不误砍柴功35 分钟前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_23435 分钟前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨38 分钟前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟2 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity3 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天3 小时前
java的threadlocal为何内存泄漏
java
caridle3 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^3 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋34 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花4 小时前
【JAVA基础】Java集合基础
java·开发语言·windows