23种设计模式详解_快速带你彻底弄懂23种设计模式-原型模式

模式定义:

指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

  1. 举个例子:对象A初始化好很多实例,如果要得到实例的拷贝如何得到?

传统的方式通过new的方式

现在我们可以在实例类中提供一个clone方法,通过这个方法拿到实例的数据。

做一个实验室项目,实验室中对一个数据可能会有n多个样品数据,他们之间的差异会非常小,传统:创建100个实验项目,new 100次

将实例类实现cloneable接口(它是一个标记接口,里面没有任何方法);

重写Object中的clone()方法,返回Computer类型,super.clone()调用的是native方法,是由JVM 实现的,完成我们数据的拷贝。

如何拿到当前实例的拷贝 :实例名.clone();

克隆方法是如何工作的呢?

在克隆的这个步骤中,我们需要注意的是当初始化的对象中包含可变引用数据的话,对于这个可变的引用数据也需要实现cloneable接口,并在该对象中重写clone()方法,否则的话,我们克隆后的数据的引用是指向原数据的,当改变原数据后,克隆对象的数据也会改变,这就不符合我们的需求了。

对于不可变属性,我们在修改原数据后,clone的数据不会发生变化。

实现如下:

public class prototypeTest {    public static void main(String[] args) throws CloneNotSupportedException {        ComputerInfo xiosad = new ComputerInfo("xiosad");        Computer computer = new Computer("sada", "sd", "dsa", "sa", "ssss", "sssaa",xiosad);        System.out.println("computer = " + computer);        Computer clone = computer.clone();        System.out.println("clone = " + clone);        //修改不可变属性CompanyName--->clone的数据中CompanyName不会发生变化        computer.setCompanyName("gaibian");        //修改可变引用类型ComputerInfo        computer.getComputerInfo().setComputerName("修改的");        System.out.println("computer = " + computer);        System.out.println("clone = " + clone);    }}class ComputerInfo{    private String computerName;    public ComputerInfo(String computerName) {        this.computerName = computerName;    }    public String getComputerName() {        return computerName;    }    public void setComputerName(String computerName) {        this.computerName = computerName;    }    @Override    public String toString() {        return super.hashCode()+" ] ComputerInfo{" +                "computerName='" + computerName + ''' +                '}';    }}class Computer implements Cloneable {    //实假设需要构建的对象的字段如下    private String computerName;    private String companyName;    private String cpu;    private String part2;    private String part3;    private String part4;    private ComputerInfo computerInfo;    public Computer() {    }    public Computer(String computerName, String companyName, String cpu, String part2, String part3, String part4,ComputerInfo computerInfo) {        this.computerName = computerName;        this.companyName = companyName;        this.cpu = cpu;        this.part2 = part2;        this.part3 = part3;        this.part4 = part4;        this.computerInfo = computerInfo;    }    public String getComputerName() {        return computerName;    }    public void setComputerName(String computerName) {        this.computerName = computerName;    }    public String getCompanyName() {        return companyName;    }    public void setCompanyName(String companyName) {        this.companyName = companyName;    }    public String getCpu() {        return cpu;    }    public void setCpu(String cpu) {        this.cpu = cpu;    }    public String getPart2() {        return part2;    }    public void setPart2(String part2) {        this.part2 = part2;    }    public String getPart3() {        return part3;    }    public void setPart3(String part3) {        this.part3 = part3;    }    public String getPart4() {        return part4;    }    public void setPart4(String part4) {        this.part4 = part4;    }    public ComputerInfo getComputerInfo() {        return computerInfo;    }    public void setComputerInfo(ComputerInfo computerInfo) {        this.computerInfo = computerInfo;    }    @Override    protected Computer clone() throws CloneNotSupportedException {        return ((Computer) super.clone());    }    @Override    public String toString() {        return super.hashCode()+" ] Computer{" +                "computerName='" + computerName + ''' +                ", companyName='" + companyName + ''' +                ", cpu='" + cpu + ''' +                ", part2='" + part2 + ''' +                ", part3='" + part3 + ''' +                ", part4='" + part4 + ''' +                ", computerInfo=" + computerInfo +                '}';    }}

运行结果:

163538bf0fe8ba346cc0dc9cbc138640.png

如何解决这个问题呢,这就需要深拷贝来实现,对于可变引用数据类型,我们也要clone它,因此对于ComputerInfo类,我们要实现Cloneable接口,修改后的ComputerInfo类:

class ComputerInfo implements Cloneable{    private String computerName;    public ComputerInfo(String computerName) {        this.computerName = computerName;    }    public String getComputerName() {        return computerName;    }    public void setComputerName(String computerName) {        this.computerName = computerName;    }    @Override    protected ComputerInfo clone() throws CloneNotSupportedException {        return ((ComputerInfo) super.clone());    }    @Override    public String toString() {        return super.hashCode()+" ] ComputerInfo{" +                "computerName='" + computerName + ''' +                '}';    }}

Computer类中的clone()方法需要设置ComputerInfo的克隆:

@Overrideprotected Computer clone() throws CloneNotSupportedException {    Computer clone = (Computer)super.clone();       ComputerInfo clone1 = this.computerInfo.clone();      clone.setComputerInfo(clone1);       return clone;}

测试运行结果:

2d383914d2502ff6d5bc1df9c8720845.png
  1. 如果可变引用特别多的话,可以利用java的序列化机制来实现深拷贝。

1)修改重写的clone()函数如下。

 @Override    protected Computer clone() throws CloneNotSupportedException {//        v1 --深复制版本一//        Computer clone = (Computer)super.clone();//        ComputerInfo clone1 = this.computerInfo.clone();//        clone.setComputerInfo(clone1);//        return clone;//        v2 --深复制-序列化//        1.定义一下输出流        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();//        2.把JVM中的数据写到流中        try {            ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream);            oos.writeObject(this);        } catch (IOException e) {            e.printStackTrace();        }      //        3.将流读到对象中        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());        try {            ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream);            Computer object = ((Computer) ois.readObject());            return object;        } catch (IOException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        return null;    }

2)序列化Computer类、ComputerInfo类(实现Serializable接口即可)

执行结果:

9ce37ea77d90bc60f46fbc956c5e38b5.png

当然深拷贝的操作不建议利用序列化,因为序列化的方式的代码实现是CPU密集型的,解析流消耗性能,速度会变慢,实际使用时需要平衡性能

应用场景:

当代码不应该依赖于需要复制的对象的具体类时,使用原型模式

优点:

1)可以不耦合具体类的情况下克隆对象

2)避免重复的初始化对象

3)更方便构建复杂对象

Spring中的源码实现:

java.util.ArrayList

org.springframework.beans.factory.support.AbstractBeanDefinition

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值