欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

硬肝系列:23种设计模式之原型模式

程序员文章站 2024-03-17 19:38:10
...

用示例代码来帮你了解原型模式

对于“设计模式”这个词大家肯定都不陌生,很多框架也用到了设计模式,但是大部分的开发者应该是没有深入的了解过,我准备硬肝下这23设计模式作为专题文章的开端,一共23种设计模式,我尽量在<23天肝完。

为什么要学习设计模式:https://blog.csdn.net/kaituozhe_sh/article/details/107922339

在我大学四年,对设计模式也没有什么概念,写代码就想着能实现就可以了,不会有设计模式那样的思想,但是当学习到了框架的时候,对于设计模式才有了一些更深入的了解,使用设计模式的代码在扩展性上会比暴力的代码更容易维护,特别是当一个程序猿离职了后,你去接手它的代码,里面是一大堆if else,这样真的会崩溃,修改都不知道从何下手
在这里插入图片描述
硬肝系列目录

23种设计模式之工厂模式:https://blog.csdn.net/ALiangXLogic/article/details/114807512
23种设计模式之抽象工厂模式:https://blog.csdn.net/ALiangXLogic/article/details/114848126
23种设计模式之建造者模式:https://blog.csdn.net/ALiangXLogic/article/details/114885519

一、什么是原型模式呢?怎么实现原型模式?

概念:在23种设计模式中,原型模式属于创建型模式,为一些重复创建并且需要耗费大量资源才创建出来的对象提升了性能

在Java中提供了一个Cloneable接口,通过继承内部的clone方法,来实现对对象的克隆

这里克隆涉及到两个概念:浅克隆和深克隆

浅克隆:只克隆对象本身,还有包含的一些基本类型属性和一个引用类型(String),也就是说克隆的对象如果是前面这些类型,则克隆一份给新的对象;如果是其他引用类型的变量,则将对象的引用地址克隆一份给新对象,也就是说原型对象的引用地址和新对象的引用地址指向的是同一个对象。

下面通过一个例子来给大家看看浅克隆:

package designModels.PrototypeMode04.qianClone;

public class K40pro {
    private String k40 = "我是k40 pro";

    public String getK40() {
        return k40;
    }

    public void setK40(String k40) {
        this.k40 = k40;
    }

    @Override
    public String toString() {
        return "我是k40 pro !!!";
    }
}
package designModels.PrototypeMode04.qianClone;

public class Xiaomi01 implements Cloneable{
	//基本数据类型
    private int count;
    //String类型
    private String Brand = "k40 pro 真难抢!!!";
    //引用数据类型
    private K40pro k40pro;

    public Xiaomi01() {
        this.k40pro = new K40pro();
        this.count = 66666;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public K40pro getK40pro() {
        return k40pro;
    }

    public String getBrand() {
        return Brand;
    }

    public void setBrand(String brand) {
        Brand = brand;
    }

    public Object clone(){
        Xiaomi01 xiaomi011 = null;
        try{
            xiaomi011 = (Xiaomi01) super.clone();
        }catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return xiaomi011;
    }


    public static void main(String[] args){
        Xiaomi01 xiaomi01 = new Xiaomi01();
        Xiaomi01 xiaomi011 = (Xiaomi01) xiaomi01.clone();
        //该对象为新克隆的对象
        System.out.println(xiaomi01 == xiaomi011);//false
        System.out.println(xiaomi01.getCount() == xiaomi011.getCount());//true
        System.out.println(xiaomi01.getBrand() == xiaomi011.getBrand());//true
        //因为浅克隆只是克隆了指向该对象的地址
        //并没有开辟一个新的空间来存储新的对象
        System.out.println(xiaomi01.getK40pro() == xiaomi011.getK40pro());//true
    }
}

还有些朋友看上面的例子有些疑惑,为什么克隆了int和String比较还是相等的,下面先测试基本类型:

public static void main(String[] args){
        Xiaomi01 xiaomi01 = new Xiaomi01();
        Xiaomi01 xiaomi011 = (Xiaomi01) xiaomi01.clone();
        //设置新的值,如果为同一个对象则两个对象的值必然一起改变
        xiaomi01.setBrand("k30 pro 真香!!");
        System.out.println(xiaomi01.getBrand() == xiaomi011.getBrand());
        System.out.println(xiaomi01.getBrand());
        System.out.println(xiaomi011.getBrand());
        //设置新的值
        xiaomi01.setCount(1024);
        System.out.println(xiaomi01.getCount());
        System.out.println(xiaomi011.getCount());
    }

测试结果:

false
k30 pro 真香!! //新设置的值
k40 pro 真难抢!!! //

1024 // 新设置的值
66666

再来看看引用类型:

public static void main(String[] args){
        Xiaomi01 xiaomi01 = new Xiaomi01();
        Xiaomi01 xiaomi011 = (Xiaomi01) xiaomi01.clone();
        //新设置引用类型内变量的值
        xiaomi01.getK40pro().setK40("我是k30 pro");
        System.out.println(xiaomi01.getK40pro().getK40());
        System.out.println(xiaomi011.getK40pro().getK40());
    }

输出结果:

我是k30 pro
我是k30 pro

从上面的结果我们可以看到,浅拷贝对于引用类型只是拷贝指向地址,并不是拷贝对象,而深拷贝则是对引用类型的对象进行拷贝,意思就是在堆中开辟了一块空间新建了一个对象

现在我们来看看深拷贝的实现模式:

主要就是将其引用对象序列化,然后反序列化,序列化是将对象转换成字节序列,反序列化是将字节序列还原成对象,使用 Serializable 序列化的方式实现深拷贝比较简单,但需要注意 serialVersionUID 的值,且 static 和 transient 类型的变量不会被序列化。

package designModels.PrototypeMode04.shenClone;

import java.io.*;

public class Xiaomi01 implements Cloneable,Serializable{
    private static final long serialVersionUID = -3943427356942430084L;
    private int count;
    private String Brand = "k40 pro 真难抢!!!";
    private K40pro k40pro;

    public Xiaomi01() {
        this.k40pro = new K40pro();
        this.count = 66666;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public K40pro getK40pro() {
        return k40pro;
    }

    public String getBrand() {
        return Brand;
    }

    public void setBrand(String brand) {
        Brand = brand;
    }

    public Object clone(){
        Xiaomi01 xiaomi011 = null;
        try{
            xiaomi011 = (Xiaomi01) super.clone();
        }catch (CloneNotSupportedException e){
            e.printStackTrace();
        }
        return xiaomi011;
    }
    public Object deepClone(){
        ByteArrayInputStream byteArrayInputStream=null;
        ObjectInputStream objectInputStream=null;
        ByteArrayOutputStream byteArrayOutputStream=null;
        ObjectOutputStream objectOutputStream=null;
        try {
            //序列化
            byteArrayOutputStream =new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);
            
            //反序列化
            byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            objectInputStream=new ObjectInputStream(byteArrayInputStream);
            Xiaomi01 xiaomi01 = (Xiaomi01) objectInputStream.readObject();
            return xiaomi01;
        } catch (ClassNotFoundException e){
            e.printStackTrace();
        }
        catch (IOException e){
            e.printStackTrace();
        }finally {
            try{
                byteArrayInputStream.close();
                byteArrayOutputStream.close();
                objectInputStream.close();
                objectOutputStream.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        return null;
    }


    public static void main(String[] args){
        Xiaomi01 xiaomi01 = new Xiaomi01();
        //调用deepClone方法实现深拷贝
        Xiaomi01 xiaomi011 = (Xiaomi01) xiaomi01.deepClone();
        xiaomi01.getK40pro().setK40("我是k30 pro");
        System.out.println(xiaomi01.getK40pro().getK40());
        System.out.println(xiaomi011.getK40pro().getK40());
    }
}

输出结果:

xiaomi01 我是k30 pro
xiaomi011 我是k40 pro

最后,通过克隆这种形式,我们可以不耗费那么多资源就完成对一个对象的创建

原型模式是一种比较简单的模式,也非常容易理解,使用一个接口、重写一个clone方法即可,但是一般不单独出现,会与其他模式一起结合使用,过两天再写一个原型模式的实现例子

完成:TO: 2021/3/17 20:28

相关标签: 硬肝系列