23种设计模式之原型模式

原型模式

1.经典案例

  • 克隆羊多利。有姓名,身高,体重,年龄等属性。可以用来当作模板,克隆10只属性完全相同的羊。
  • 三好学生奖状。有姓名,学校,获奖时间等属性。奖状可以当作模板,打印多份,使用时只需要修改姓名,学校,获奖时间。

常规解法

1.定义sheep实体类,生成构造方法、getter和setter方法、toString方法

2.实例化10个对象

缺点:

效率低,每次创建对象都需要获取原始对象的属性,不能动态获取对象运行时的状态。

新思路-原型模式

2.原型模式定义

【创建型】设计模式。允许另外一个对象再创建另外一个可定制的对象

用原型实例指定创建的对象,并通过拷贝原型,创建新对象,同时保证性能

3.工作原理

  • 原型类声明克隆自己的接口
  • Client类让具体的原型类对象克隆自己,创建一个新的对象

图片引用其他人的,不是我画的

  • Prototype:声明一个克隆自己的接口
  • client:客户端让一个原型对象克隆自己
  • ConcretePrototype:实现一个克隆自己的操作

4.原型模式分类

- 浅拷贝

代码思路:

在实体类的基础上实现Cloneable接口,重写clone方法

Demo中调用克隆对象

代码演示:

🐏的实体类

package com.henji.clone;

/**
 * Sheep类基础上实现Cloneable接口,重写clone方法。
 *
 * @author henji
 * @date 2023/3/6 19:08
 */
public class Sheep implements Cloneable {
    private String name;
    private int age;

    @Override
    protected Object clone () throws CloneNotSupportedException {
        Sheep sheep = null;
        sheep = (Sheep) super.clone ();
        return sheep;
    }

    /*******省略构造方法、setter、getter、toString方法*******/

}

🐏的实现类

package com.henji.clone;

/**
 * @author henji
 * @date 2023/3/6 20:06
 */
public class Demo {
    public static void main (String[] args) throws CloneNotSupportedException {
        Sheep sheep = new Sheep ("喜羊羊", 2);
        
        Object c1 = sheep.clone ();
        Object c2 = sheep.clone ();
        Object c3 = sheep.clone ();

        System.out.println (c1 + "===" + c1.hashCode ());
        System.out.println (c2 + "===" + c2.hashCode ());
        System.out.println (c3 + "===" + c3.hashCode ());
    }
}

运行结果

在这里插入图片描述

总结:

  • 三个对象的哈希值不同,说明拷贝进行是值传递,而不是引用传递
继续往下看:

此时慢羊羊也来凑热闹了,再新建一个🐏的实体类,并再Sheep类添加一个引用属性。再拷贝一遍

新建的慢羊羊实体类

package com.henji.clone;

/**
 * 慢羊羊的实体类
 *
 * @author henji
 * @date 2023/3/6 19:08
 */
public class Sheep2 {
    private String name;
    private int age;
    
    /*******省略构造方法、setter、getter、toString方法*******/
}

添加了慢羊羊的引用属性的🐏实体类

package com.henji.clone;

/**
 * Sheep类基础上实现Cloneable接口,重写clone方法。
 *
 * @author henji
 * @date 2023/3/6 19:08
 */
public class Sheep implements Cloneable {
    private String name;
    private int age;
    public Sheep2 sheep2;//引用慢羊羊

    @Override
    protected Object clone () throws CloneNotSupportedException {
        Sheep sheep = null;
        sheep = (Sheep) super.clone ();
        return sheep;
    }
    /*******省略构造方法、setter、getter、toString方法*******/
}

实例化慢羊羊

package com.henji.clone;

/**
 * @author henji
 * @date 2023/3/6 20:06
 */
public class Demo {
    public static void main (String[] args) throws CloneNotSupportedException {
        Sheep sheep = new Sheep ("喜羊羊", 2);
        sheep.sheep2 = new Sheep2 ("慢羊羊", 8);

        Sheep c1 = (Sheep) sheep.clone ();
        Sheep c2 = (Sheep) sheep.clone ();
        Sheep c3 = (Sheep) sheep.clone ();
        
        System.out.println (c1 + "===" + c1.hashCode () + ":::" + c1.sheep2 + "===" + c1.sheep2.hashCode ());
        System.out.println (c2 + "===" + c2.hashCode () + ":::" + c2.sheep2 + "===" + c2.sheep2.hashCode ());
        System.out.println (c3 + "===" + c3.hashCode () + ":::" + c3.sheep2 + "===" + c3.sheep2.hashCode ());
    }
}

运行结果

在这里插入图片描述

总结:

  • 拷贝的三个喜羊羊对象哈希地址各不相同,依旧发生了值传递,但三个慢羊羊的地址完全相同,没有发生拷贝动作,地址指向克隆前的同一个对象。(如何让慢羊羊的拷贝对象也发生值传递?)
特征:
  • 浅拷贝使用默认的clone()方法实现
  • 基本数据类型的成员变量,浅拷贝会直接进行值传递
  • 引用数据类型的成员变量,浅拷贝会进行引用传递

- 深拷贝

代码思路:
  • 慢羊羊的实体类也实现Cloneable接口
  • 实体类实现序列化接口,不实现Cloneable接口

实现Cloneable接口,重写clone

/**
 * 慢羊羊的实体类
 *
 * @author henji
 * @date 2023/3/6 19:08
 */
public class Sheep2 implements Cloneable {
    private String name;
    private int age;

    /*
    使用默认clone方法
    */
    @Override
    protected Object clone () throws CloneNotSupportedException {
        return super.clone ();
    }
}

在喜羊羊的实体类clone方法中调用慢羊羊的clone方法

package com.henji.clone;

/**
 * Sheep类基础上实现Cloneable接口,重写clone方法。
 *
 * @author henji
 * @date 2023/3/6 19:08
 */
public class Sheep implements Cloneable {
    private String name;
    private int age;
    public Sheep2 sheep2;

    @Override
    protected Object clone () throws CloneNotSupportedException {
        Object deep = null;
        //对基本数据类型拷贝
        deep = super.clone ();
        //对引用数据类型拷贝
        Sheep sheep = (Sheep) deep;
        sheep.sheep2 = (Sheep2) sheep2.clone ();
        return sheep;
    }
}

再次运行Demo类

运行结果:

在这里插入图片描述

总结:

  • 两个类(基本数据类型,引用数据类型)的拷贝,都实现了值传递,达成了深拷贝。
特征:
  • 基本数据类型和引用数据类型,深拷贝都会对其进行值传递【复制】
通过序列化实现深拷贝
慢羊羊的实体类实现序列化接口,不需要再实现Cloneable接口
package com.henji.clone;

import java.io.Serializable;

/**
 * 慢羊羊的实体类
 *
 * @author henji
 * @date 2023/3/6 19:08
 */
public class Sheep2 implements Serializable {
    private String name;
    private int age;
    }
喜羊羊的实体类也实现序列化接口,并使用流
package com.henji.clone;

import java.io.*;

/**
 * Sheep类基础上实现Cloneable接口,重写clone方法。
 *
 * @author henji
 * @date 2023/3/6 19:08
 */
public class Sheep implements Serializable {
    private String name;
    private int age;
    public Sheep2 sheep2;

    /**
     * 深拷贝
     *
     * @return
     */
    Object 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);
            Sheep sheep = (Sheep) ois.readObject ();

            return sheep;
        } catch (IOException e) {
            throw new RuntimeException (e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException (e);
        } finally {
            try {
                bos.close ();
                oos.close ();
                bis.close ();
                ois.close ();
            } catch (IOException e) {
                throw new RuntimeException (e);
            }
        }

    }

    /*******省略构造方法、setter、getter、toString方法*******/
客户端调用
package com.henji.clone;

/**
 * @author henji
 * @date 2023/3/6 20:06
 */
public class Demo {
    public static void main (String[] args) throws CloneNotSupportedException {
        Sheep sheep = new Sheep ("喜羊羊", 2);
        sheep.sheep2 = new Sheep2 ("慢羊羊", 8);

        Sheep c1 = (Sheep) sheep.deepClone ();
        Sheep c2 = (Sheep) sheep.deepClone ();
        Sheep c3 = (Sheep) sheep.deepClone ();

        System.out.println (c1 + "===" + c1.hashCode () + ":::" + c1.sheep2 + "===" + c1.sheep2.hashCode ());
        System.out.println (c2 + "===" + c2.hashCode () + ":::" + c2.sheep2 + "===" + c2.sheep2.hashCode ());
        System.out.println (c3 + "===" + c3.hashCode () + ":::" + c3.sheep2 + "===" + c3.sheep2.hashCode ());
    }
}

- 深拷贝和浅拷贝的区别

在于对引用数据类型的成员变量的拷贝

  • 浅拷贝对引用数据类型进行引用传递
  • 深拷贝对引用数据类型进行值传递

5.特点:

优点

  • 动态获取对象运行时的状态,不需要重新初始化对象
  • 原始对象发生增加或者减少属性,其他克隆对象也会发生变化,无须修改代码
  • 创建的新对象比较复杂时,可以使用原型模式简化对象创建过程,提高效率

缺点

  • 需要为每一个类重写一个克隆方法
  • 对已存在的类进行改造需要修改源码,违背了开闭原则
  • 对象存在多层引用,每一层对象都必须支持深拷贝,并且需要编写复杂的代码

6.应用场景

设计模式之原型设计应用-制作奖状

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值