原型模式

原型模式

需求:
场景描述简单来说,就是OA系统中,一个员工填写周报的内容,每个星期大多数位置内容相同需要修改的就只有少数部分。如果每个月都要全部进行填写,那么久又麻烦效率又低,故可以保存周报模板,只需要修改不同部分即可。

浅克隆

class Worker implements Cloneable{
    private int id;
    private String context;
    private String sex;
    private Date date;

	//注意要将重写的clone方法的权限修饰符由protected改为public
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
	// .... 此处省略get,set,toString方法

    public Worker(int id, String context, String sex, Date date) {
        this.id = id;
        this.context = context;
        this.sex = sex;
        this.date = date;
    }
}


//上为服务端,下为客户端(我们角色为客户,可以随意修改客户端内容,却不能修改服务端内容)
//==============================================
public class AppTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建一组数据
        Worker worker = new Worker(1, "刘备", "男", new Date());
        System.out.println(worker);

        //过一段时间后在想要一组数据,但是只修改想要修改的布冯,其余部分不用修改
        Worker clone = (Worker) worker.clone();
        clone.setContext("诸葛亮");
        clone.setSex("女");
        System.out.println(clone);
    }
}

注意:

  1. 克隆会得到一个新的对象
  2. 克隆是直接复制内存中的二进制文件,不会引起全构造器的使用,效率更高
  3. 克隆出来的对象是两个不同的空间,他们的地址是不一样的

缺点:
克隆后,修改了一个对象的属性,那么另一个对象的属性也会发生变化
比如:如果这时候我们修改了里面的时间对象,如修改了代码:
修改时间对象里面的time值
那么结果:
clone后修改对象属性后克隆原本对象的值也会改变
原因: 浅拷贝就是将原来的对象的二进制文件原模原样的复制过来,包括二进制中的对象的内存地址也是原模原样的复制过来,如果修改了拷贝过来的对象中的属性对象的值,那么由于两个指向的地址相同,那么拷贝之前的对象内存的值也会发生改变。
浅拷贝详细模型图:
浅拷贝详细模型图
含义:原对象里面的对象属性原来执行的是内存地址为200的对象,浅拷贝将原对象二进制文件原模原样拷贝了过来,包括对象内指向200的地址,这时候,我们在拷贝出来的对象内修改对象内指向200的对象的属性,那么由于原对象内的对象属性也是指向200的内存地址,故值也会改变。

深拷贝

深拷贝代码修改(只是修改了重写的clone部分)

class Worker implements Cloneable{
    private int id;
    private String context;
    private String sex;
    private Date date;

	//注意修改访问修饰符为public
    @Override
    public Object clone() throws CloneNotSupportedException {
        //先克隆一份该对象
        Worker clone = (Worker) super.clone();
        //将对象中的对象也进行一次克隆
        Date date = (Date) clone.getDate().clone();
        //将克隆出来的属性传入拷贝出来的对象中
        clone.setDate(date);
        return clone;
    }
    
    // .... 此处省略get,set,toString方法
    
    public Worker(int id, String context, String sex, Date date) {
        this.id = id;
        this.context = context;
        this.sex = sex;
        this.date = date;
    }
}


//原型模式
//==============================================
public class AppTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建一组数据
        Worker worker = new Worker(1, "刘备", "男", new Date());
        System.out.println(worker);

        //过一段时间后在想要一组数据,但是只修改想要修改的布冯,其余部分不用修改
        Worker clone = (Worker) worker.clone();
        clone.setContext("诸葛亮");
        clone.setSex("女");
        clone.getDate().setTime(0);
        System.out.println(clone);
        System.out.println(worker);
    }
}

修改的部分只有clone里面的部分,我们在拷贝的时候,顺便将内部对象(Date)进行拷贝一份,并将它重新赋值给clone出来的对象。

拷贝详细模型图:
深拷贝详细模型图
简单来说就是将对象内的对象也进行一次拷贝,并将拷贝出来的赋值给外面拷贝的对象,就不会产生对象内部的对象内存地址一样的问题。
缺点: 如果对象嵌套太深,则拷贝起来就很麻烦 (也就是说如果一个对象包含一个对象,里面的对象又包含一个对象…这样拷贝就得一个对象一个对象的进行拷贝)

改善(序列化方式拷贝)

序列化天生就是一种深拷贝

存于磁盘中的序列化拷贝
class Worker implements Cloneable,Serializable{
    private int id;
    private String context;
    private String sex;
    private Date date;

    @Override
     public Object clone() throws CloneNotSupportedException {
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("F://o.txt"));
            oos.writeObject(this);//序列化时,对象的所有层级关系会被自动处理
            oos.close();

            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("F://o.txt"));
            Object o = ois.readObject();
            ois.close();
            return o;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
    //此处省略get,set,toString方法

    public Worker(int id, String context, String sex, Date date) {
        this.id = id;
        this.context = context;
        this.sex = sex;
        this.date = date;
    }
}


//原型模式
//==============================================
public class AppTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建一组数据
        Worker worker = new Worker(1, "刘备", "男", new Date());
        System.out.println(worker);

        //过一段时间后在想要一组数据,但是只修改想要修改的布冯,其余部分不用修改
        Worker clone = (Worker) worker.clone();
        clone.setContext("诸葛亮");
        clone.setSex("女");
        clone.getDate().setTime(0);
        System.out.println(clone);
        System.out.println(worker);
    }
}

序列化会自动处理对象内的层级关系
缺点: 程序中存在盘符,则与Windows耦合了,位置不应该写死,linux下面不存在盘符,所以该程序转到linux中不可用

存于内存中的序列化拷贝(我们推荐的原型模式的方式)
class Worker implements Cloneable,Serializable{
    private int id;
    private String context;
    private String sex;
    private Date date;

    @Override
    public Object clone() throws CloneNotSupportedException {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(out);
            oos.writeObject(this);
            oos.close();
            //从内存中取出数据
            byte[] bytes = out.toByteArray();

            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
            Object o = ois.readObject();
            ois.close();
            return o;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
    //

    public Worker(int id, String context, String sex, Date date) {
        this.id = id;
        this.context = context;
        this.sex = sex;
        this.date = date;
    }
}


//原型模式
//==============================================
public class AppTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建一组数据
        Worker worker = new Worker(1, "刘备", "男", new Date());
        System.out.println(worker);

        //过一段时间后在想要一组数据,但是只修改想要修改的布冯,其余部分不用修改
        Worker clone = (Worker) worker.clone();
        clone.setContext("诸葛亮");
        clone.setSex("女");
        clone.getDate().setTime(0);
        System.out.println(clone);
        System.out.println(worker);

    }
}

创建对象的四种方式:1、new 2、反射 3、序列化 4、克隆

以上内容为课后总结,如有侵权,请告知本人!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值