设计模式-原型模式(4)

本文深入剖析了Java中的原型模式,解释了为何需要原型模式来提高对象创建的效率。通过示例展示了如何实现浅拷贝和深拷贝,讨论了浅拷贝导致的引用对象共享问题,并给出了解决策略。此外,还提到了使用序列化进行深拷贝的方法及其优缺点。最后,文章总结了原型模式在创建对象方面的优势以及Java创建对象的多种方式。
摘要由CSDN通过智能技术生成

原型模式


为什么需要原型模式

在这里插入图片描述


实例

  • 使用原型模式解决上面问题:
      1. 必须让目标类实现cloneable接口,该接口中没有任何抽象方法。这样的接口仅仅是一个“标记接口”,作用是告诉jvm,任何实现该接口的对象可以被clone。
      1. 必须重写java.lang.Object的clone方法,一定要把该方法的访问修饰符重写为public!!不然无法调用clone方法。
import java.util.Date;

class WeekReport implements Cloneable{
    private int id;
    private String emp; // employer private员工
    private String summary;
    private String plan;
    private String suggestion;
    private Date time;

    public WeekReport(){
        System.out.println("构造方法!");
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setEmp(String emp) {
        this.emp = emp;
    }

    public void setSummary(String summary) {
        this.summary = summary;
    }

    public void setPlan(String plan) {
        this.plan = plan;
    }

    public void setSuggestion(String suggestion) {
        this.suggestion = suggestion;
    }

    public void setTime(Date time) {
        this.time = time;
    }

    public String getEmp() {
        return emp;
    }

    public String getSummary() {
        return summary;
    }

    public String getPlan() {
        return plan;
    }

    public String getSuggestion() {
        return suggestion;
    }

    public Date getTime() {
        return time;
    }

    @Override
    public String toString() {
        return "WeekReport{" +
                "id=" + id +
                ", emp='" + emp + '\'' +
                ", summary='" + summary + '\'' +
                ", plan='" + plan + '\'' +
                ", suggestion='" + suggestion + '\'' +
                ", time=" + time +
                '}';
    }

    @Override
    public Object clone() throws CloneNotSupportedException {   // 修饰符要比父类宽松,父类是protected
        return super.clone();
    }
}


public class Test00 {
    public static void main(String[] args) throws Exception {
        WeekReport wr = new WeekReport();
        wr.setEmp("zgy");
        wr.setSummary("eat");
        wr.setPlan("no");
        wr.setSuggestion("no");
        wr.setTime(new Date());
        wr.setId(1);
        System.out.println(wr);

        // 第二个周报只有Plan不一样,但是也要重新设置,不好
        WeekReport wr2 = new WeekReport();
        wr2.setEmp("zgy");
        wr2.setSummary("eat");
        wr2.setPlan("YES");
        wr2.setSuggestion("no");
        wr2.setTime(new Date());
        wr2.setId(1);
        System.out.println(wr2);

        // 原型模式修改,clone是直接内存复制一份,不会重复调用构造方法。2份内存地址不同
        WeekReport wr3 = (WeekReport) wr.clone();
        // 只要设置变化的参数
        wr3.setId(3);
        System.out.println(wr3);

    }
}



问题1:

		WeekReport wr = new WeekReport();
        wr.setEmp("zgy");
        wr.setSummary("eat");
        wr.setPlan("no");
        wr.setSuggestion("no");
        wr.setTime(new Date());
        wr.setId(1);
        System.out.println(wr);
        
        WeekReport wr3 = (WeekReport) wr.clone();
        wr3.setId(3);
        wr3.getTime().setTime(0);
        System.out.println(wr);
        System.out.println(wr3);

构造方法!
WeekReport{id=1, emp='zgy', summary='eat', plan='no', suggestion='no', time=Fri Jul 09 15:45:54 CST 2021}
WeekReport{id=1, emp='zgy', summary='eat', plan='no', suggestion='no', time=Thu Jan 01 08:00:00 CST 1970}
WeekReport{id=3, emp='zgy', summary='eat', plan='no', suggestion='no', time=Thu Jan 01 08:00:00 CST 1970}

Data.setTime(0),设置毫秒数,自1970.1.1 00:00:00以来的

如上所示,wr3克隆自wr,wr3.getTime返回Data,然后调用setTime实际上是Data.setTime()。
因为这种克隆是浅拷贝,所以引用的对象还是同一个。

在这里插入图片描述

修改的是一个new Data();
在这里插入图片描述

  • 如何解决上面问题1:
    在这里插入图片描述
	@Override
    public Object clone() throws CloneNotSupportedException {   // 修饰符要比父类宽松,父类是protected
    	// 克隆的是整个WeekReport,上图的长条部分
        WeekReport clone_weekReport = (WeekReport)super.clone();
		// 克隆的是new Data()部分
        Date cloneData = (Date) clone_weekReport.getTime().clone();
		// 修改克隆的WeekReport,把其中setTime部分引用到新克隆的Data,即图中300(Data的地址)
        clone_weekReport.setTime(cloneData);
        return clone;
    }

上述方式是深拷贝
在这里插入图片描述

问题2:

  • 上面方式虽然能够解决浅拷贝的问题,但是如果WeekReport中有XXX属性,而XXX属性又有别的属性,如此嵌套。就需要clone很多,不好。
  • 使用序列化。
WeekReport implements Serializable

	@Override
    public Object clone() throws CloneNotSupportedException {   // 修饰符要比父类宽松,父类是protected
        try {
            OutputStream out = new FileOutputStream("./a.txt");
            ObjectOutputStream oos = new ObjectOutputStream(out);
            oos.writeObject(this);  // 序列化时候,对象的所有属性层级关系会被序列化自动处理
            oos.close();

            InputStream in = new FileInputStream("./a.txt");
            ObjectInputStream ois = new ObjectInputStream(in);
            Object clone = ois.readObject();
            ois.close();
            return clone;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

问题3:

  • 写在硬盘上不好跨平台,最好不要操作硬盘(虽然可以相对路径)。
  • 写入内存

在这里插入图片描述


总结

  • 用原型实例指定创建对象的种类,通过拷贝这些原型创建的对象来代替new Object();
  • java创建对象四种方式:1. new构造 2. 反射 3. 克隆 4. 反序列化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值