原型模式

一、概述

孙悟空拔毛变小猴
《西游记》中,孙悟空拔毛变小猴的故事人人皆知。在面向对象软件设计领域,根据自己的形状复制(克隆)出与自己一摸一样的技巧叫做原型模式。
原型模式的定义如下:
原型模式(Prototype Pattern):使用原型实例指定待创建对象的类型,并通过复制这个原型来创建新的对象。

二、结构与实现

Prototype: 抽象原形类
ConcretePrototype: 具体原形类
Client: 客户类
原型模式结构图

三、浅克隆

根据原形对象的引用类型的成员变量是否被复制,原形模式的两种克隆机制分为浅克隆和深克隆。
浅克隆示意图
在浅克隆中,如果原型对象的成员变量是值类型(如int,double,byte,boolean,char等基本数据类型),则复制一份,如果是引用类型(如类、接口、数组等复杂数据类型),则将引用对象的地址复制一份给克隆对象。
所有的java类均继承java.lang.Object类,Object类提供了一个clone()方法,可以将一个Java对象复制一份。因此可以直接使用Object的clone()方法实现原型对象的浅克隆。但是能实现克隆的原型对象类必须实现Cloneable接口,标识这个类支持复制。如果一个类没实现Cloneable接口,但调用了clone()方法,java编译器会抛出CloneNotSupportedException异常。

四、深克隆

深克隆示意图

在深克隆中,原型对象的成员对象无论是值类型还是引用类型都将复制一份。
在java中,可以使用序列化实现深克隆。把原型对象写入流中,然后把该流写出到克隆对象,这个过程不但可以复制原型对象的值类型成员变量,还可以复制原型对象的引用类型成员变量,从而实现深克隆。但实现序列化的类必须实现Serializable接口。

五、使用案例

案例:某公司员工每周都要用系统提交周报,但大家发现每周的周报都大同小异,内容很相似,所以急需快速创建相同或相似周报的功能,包括周报的附件。
请用原型模式改进现有系统,增加复制周报功能。
浅克隆解决方案
工作周报创建模块结构图(浅克隆)

package com.mzy.shejimoshi.PrototypePatternOfShallow;

public class Attachment {
    private String name;
    public void  setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void download() {
        System.out.println("下载附件,文件名为"+name);
    }
}
package com.mzy.shejimoshi.PrototypePatternOfShallow;

public class WeeklyLog implements Cloneable {
    private Attachment attachment;
    private String name;
    private String date;
    private String content;
    public void setAttachment(Attachment attachment) {
        this.attachment = attachment;
    }
    public Attachment getAttachment() {
        return attachment;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setDate(String date) {
        this.date = date;
    }
    public String getDate() {
        return date;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public String getContent() {
        return content;
    }
    @Override
    public WeeklyLog clone() {
        Object obj = null;
        try {
            obj = super.clone();
            return (WeeklyLog)obj;
        } catch (CloneNotSupportedException e) {
            System.out.println("不支持复制!");
            return null;
        }
    }

}
package com.mzy.shejimoshi.PrototypePatternOfShallow;

import java.nio.file.WatchEvent;

public class Client {
    public static void main(String [] args) {
        WeeklyLog log_previous = new WeeklyLog();
        Attachment attachment = new Attachment();
        log_previous.setAttachment(attachment);
        WeeklyLog log_new = log_previous.clone();
        System.out.println("周报是否相同:"+(log_previous == log_new));
        System.out.println("附件是否相同:"+(log_previous.getAttachment() == log_new.getAttachment()));
    }
}

执行结果如下

周报是否相同:false
附件是否相同:true

深克隆解决方案如下
在这里插入图片描述

package com.mzy.shejimoshi.PrototypePatternOfDeep;

import java.io.Serializable;

public class Attachment implements Serializable {
    private String name;
    public void  setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void download() {
        System.out.println("下载附件,文件名为"+name);
    }
}
package com.mzy.shejimoshi.PrototypePatternOfDeep;

import java.io.*;

public class WeeklyLog implements Serializable {
    private Attachment attachment;
    private String name;
    private String date;
    private String content;
    public void setAttachment(Attachment attachment) {
        this.attachment = attachment;
    }
    public Attachment getAttachment() {
        return attachment;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setDate(String date) {
        this.date = date;
    }
    public String getDate() {
        return date;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public String getContent() {
        return content;
    }

    public WeeklyLog deepClone() throws IOException, ClassNotFoundException, OptionalDataException{
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bao);
        oos.writeObject(this);
        ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (WeeklyLog)ois.readObject();
    }
}
package com.mzy.shejimoshi.PrototypePatternOfDeep;

public class Client {
    public static void main(String [] args) {
        WeeklyLog log_previous = new WeeklyLog();
        WeeklyLog log_new = null;
        Attachment attachment = new Attachment();
        log_previous.setAttachment(attachment);
        try {
            log_new = log_previous.deepClone();
        } catch (Exception e) {
            System.out.println("克隆失败");
        }
        System.out.println("周报是否相同:"+(log_previous == log_new));
        System.out.println("附件是否相同:"+(log_previous.getAttachment() == log_new.getAttachment()));
    }
}

执行结果如下

周报是否相同:false
附件是否相同:false
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值