Java设计模式——原型模式

释放双眼,带上耳机,听听看~!

Java设计模式——原型模式

面向对象编程,时时刻刻与对象打交道,有时候获取一个实例化的对象非常麻烦。比如一个需要访问数据库关联大量数据表才能得到一个实例,比如对象的属性非常非常多,通过构造函数获取对象需要初始化很多对象,比较麻烦,浪费内存。类似这样的场景就需要原型模式解决问题啦。

原型模式:说白了就是更简单的获取相同或相似的对象实例。可以理解为复制克隆

下面了解两个概念

浅克隆:克隆出来的对象实例一模一样,对象的属性如果是引用数据类型,那么他么指向同一个地址值。无论是修改原来的对象,还是修改克隆出来的对象,只要是引用数据类型修改了,那么两个对象同时被修改,因为他们共享同一地址值。

深克隆:克隆出来的对象实例也是一模一样的,但是他们的引用属性也被克隆了,两个对象虽然一模一样,但是没有任何关联。修改其中一个对象,不影响另一个对象。

需求:实现电子发票对象的克隆,电子发票具有票头、票号、名称、单位、公司、颜色、监制印章、公司印章、是否有效等等对象属性。制作一张发票还是很麻烦的,所以利用原型模式快速复制发票对象,高效完成需求。

提供一个原型接口,便于原型管理和业务扩展。

/**
 * @description: 原型模式原型接口
 * @author: lmc
 * @create: 2019-05-29 20:32
 **/
public interface Prototype {

    /**
     * @description: 获取浅克隆对象
     * @return java.lang.Object
     * @date 2019/5/29 20:35
     * @author lmc
     */
    Prototype getShallowCloneInstance() throws CloneNotSupportedException;
    /**
     * @description: 获取深克隆对象
     * @return com.lmc.gp12380.pattern.prototype.Prototype
     * @date 2019/5/30 21:15
     * @author lmc
     */
    Prototype getDeepCloneInstance(Prototype prototype);

}

提供一个工具类,利用序列化实现深克隆;当然,也可以按照业务需求,把需要克隆类的所有引用对象类全部实现浅克隆,这样也是一个深克隆对象了,但是这种方法很麻烦,容易忽略对象没有去实现浅克隆。

/**
 * @description: 原型工具类
 * @author: lmc
 * @create: 2019-05-30 21:27
 **/

public class PrototypeUtil {
    /**
     * @description: 通过序列化获取一个深度克隆的对象
     * @param prototype
     * @return com.lmc.gp12380.pattern.prototype.Prototype
     * @date 2019/5/30 21:34
     * @author lmc
     */
    public static Prototype getSerializInstance(Prototype prototype){
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(prototype);
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            Prototype copy = (Prototype)ois.readObject();
            bos.flush();
            bos.close();
            ois.close();
            return copy;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

电子发票印章图片类

/**
 * @description: 电子发票印章图片
 * @author: lmc
 * @create: 2019-05-29 21:21
 **/

public class Image implements Serializable,Prototype,Cloneable {
    /**
     * 颜色
     */
    private String color=\"red\";
    /**
     * 高度
     */
    private Integer height=10;
    /**
     * 宽度
     */
    private Integer width=8;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public Integer getHeight() {
        return height;
    }

    public void setHeight(Integer height) {
        this.height = height;
    }

    public Integer getWidth() {
        return width;
    }

    public void setWidth(Integer width) {
        this.width = width;
    }

    @Override
    public String toString() {
        return \"Image{\" +
                \"color=\'\" + color + \'\\\'\' +
                \", height=\" + height +
                \", width=\" + width +
                \'}\';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public Prototype getShallowCloneInstance() throws CloneNotSupportedException {
        return (Prototype) clone();
    }

    public Prototype getDeepCloneInstance(Prototype prototype) {
        return PrototypeUtil.getSerializInstance(prototype);
    }
}
/**
 * @description: 电子印章
 * @author: lmc
 * @create: 2019-05-29 21:19
 **/
public class Seal implements Serializable,Cloneable,Prototype {
    /**
     * 印章名称
     */
    private String name;
    /**
     * 已知图片
     */
    private Image image;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Image getImage() {
        return image;
    }

    public void setImage(Image image) {
        this.image = image;
    }

    @Override
    public String toString() {
        return \"Seal{\" +
                \"name=\'\" + name + \'\\\'\' +
                \", image=\" + image +
                \'}\';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public Prototype getShallowCloneInstance() throws CloneNotSupportedException {
        return (Prototype) clone();
    }

    public Prototype getDeepCloneInstance(Prototype prototype) {
        return PrototypeUtil.getSerializInstance(prototype);
    }
}
/**
 * @description: 电子发票
 * @author: lmc
 * @create: 2019-05-29 20:36
 **/
public class Invoice implements Cloneable,Serializable,Prototype {

    /**
     * 票头
     */
    private String ticketHeader;
    /**
     * 票号
     */
    private int ticketNo;
    /**
     * 发票联名称
     */
    private String name;
    /**
     * 发票联颜色
     */
    private String color;
    /**
     * 发票联公司
     */
    private String company;
    /**
     * 公司印章
     */
    private Seal companySeal;
    /**
     * 监制印章
     */
    private Seal supervisedSeal;
    /**
     * 是否有效
     */
    private Boolean effective;

    public String getTicketHeader() {
        return ticketHeader;
    }

    public void setTicketHeader(String ticketHeader) {
        this.ticketHeader = ticketHeader;
    }

    public int getTicketNo() {
        return ticketNo;
    }

    public void setTicketNo(int ticketNo) {
        this.ticketNo = ticketNo;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public Seal getCompanySeal() {
        return companySeal;
    }

    public void setCompanySeal(Seal companySeal) {
        this.companySeal = companySeal;
    }

    public Seal getSupervisedSeal() {
        return supervisedSeal;
    }

    public void setSupervisedSeal(Seal supervisedSeal) {
        this.supervisedSeal = supervisedSeal;
    }

    public Boolean getEffective() {
        return effective;
    }

    public void setEffective(Boolean effective) {
        this.effective = effective;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return \"Invoice{\" +
                \"ticketHeader=\'\" + ticketHeader + \'\\\'\' +
                \", ticketNo=\" + ticketNo +
                \", name=\'\" + name + \'\\\'\' +
                \", color=\'\" + color + \'\\\'\' +
                \", company=\'\" + company + \'\\\'\' +
                \", companySeal=\" + companySeal +
                \", supervisedSeal=\" + supervisedSeal +
                \", effective=\" + effective +
                \'}\';
    }

    public Prototype getShallowCloneInstance() throws CloneNotSupportedException {
        return (Prototype)clone();
    }

    public Prototype getDeepCloneInstance(Prototype prototype) {
        return PrototypeUtil.getSerializInstance(prototype);
    }
}

电子发票Invoice类 包含了印章Seal类;Seal印章类包含了Image类 ;Invoice、Seal、Image全部实现了

PrototypeCloneableSerializable接口。

clone():是Object类的方法,该方法能够快速复制一个对象,属于浅克隆,引用对象属性不复制。

Cloneable接口:实现该接口才可以调用clone()方法。

Serializable接口:类实现该接口,类的对象才能被序列化和反序列化。

测试代码

/**
 * @description: 原型模式测试
 * @author: lmc
 * @create: 2019-05-29 21:46
 **/
public class PrototypeClientTest {

    public static void main(String[] args) throws CloneNotSupportedException {

        Invoice invoice=new Invoice();
        invoice.setColor(\"bule\");
        invoice.setTicketNo(1);
        invoice.setEffective(false);
        invoice.setCompanySeal(new Seal());
        //测试浅克隆
        //Invoice invoiceClone = (Invoice) invoice.getShallowCloneInstance();
        //
        Invoice invoiceClone = (Invoice) invoice.getDeepCloneInstance(invoice);
        /**
         * 验证对象是否同一个。
         */
        System.out.println(\"invoice_\"+invoice.hashCode());
        System.out.println(\"Clone_invoice_\"+invoiceClone.hashCode());
        System.out.println(\"验证对象_\"+(invoice==invoiceClone));
        /**
         * 验证基本数据类型是否相等。
         */
        System.out.println(\"getTicketNo_\"+invoice.getTicketNo());
        System.out.println(\"Clone_getTicketNo_\"+invoiceClone.getTicketNo());
        System.out.println(\"验证基本数据类型_\"+(invoice.getTicketNo()==invoiceClone.getTicketNo()));
        /**
         * 验证引用数据类型是否相等
         */
        System.out.println(\"getColor_\"+invoice.getColor().hashCode());
        System.out.println(\"Clone_getColor_\"+invoiceClone.getColor().hashCode());
        System.out.println(\"验证引用数据类型_\"+(invoiceClone.getColor() == invoice.getColor()));

        System.out.println(\"getCompanySeal_\"+invoice.getCompanySeal().hashCode());
        System.out.println(\"Clone_getCompanySeal_\"+invoiceClone.getCompanySeal().hashCode());
        System.out.println(\"验证引用数据类型_\"+(invoice.getCompanySeal() == invoiceClone.getCompanySeal()));
          System.out.println(\"____________________________________________________________\");
        /**
         * 验证基本数据类型修改
         */
        invoice.setTicketNo(2);
        System.out.println(\"验证基本数据类型修改\"+invoice);
        System.out.println(\"验证基本数据类型修改\"+invoiceClone);
        /**
         * 验证基本数据类型保包装类
         */
        invoice.setEffective(true);
        System.out.println(\"验证基本数据类型包装类\"+invoice);
        System.out.println(\"验证基本数据类型包装类\"+invoiceClone);
        /**
         * 验证引用数据类型
         */
        invoice.getCompanySeal().setName(\"验证引用数据类型\");
        System.out.println(\"验证引用数据类型\"+invoice);
        System.out.println(\"验证引用数据类型\"+invoiceClone);
    }
}

测试深克隆结果
Java设计模式——原型模式

深克隆的对象和原对象 是两个独立的对象,虽然他们的内容相同,但是他们没有任何关联。

测试浅克隆结果
Java设计模式——原型模式

浅克隆的对象和原对象也是两个对象,但是他们的引用属性对象是共享同一个对象的。上面修改公司印章,克隆对象的公司印章也修改了。基本数据类型和基本数据类型的包装类型不共享。

浅克隆模型图
Java设计模式——原型模式

对于浅克隆:栈内存中基本数据类型存储的是值,引用数据类型存储的是引用地址值。浅克隆对所有的基本数据类型进行拷贝,引用数据类型拷贝引用地址值。注意:对于基本数据类型包装类型、String类型,还有基本数据类型,只要对其进行赋值操作,就相当于从新创建了对象,之前的对象或者值就成了不可达状态,只能被垃圾回收器回收了。虽然基本数据类型的包装类型和String都是引用数据类型,但是无法证明他们是共享同一个地址值(希望大神解惑)。

深克隆模型图
Java设计模式——原型模式

对于深克隆:深克隆对所有的数据都进行了拷贝,不论是基本数据类型还是引用数据类型。两个对象之间没有任何关联关系,完完全全是独立自主的,虽然他们长得一样。

总结:所有的程序都是为业务服务的,按照业务需求,如果原型模式获取对象更简单,更合理,那么就应该使用原型模式,如果使用原型模式反而让对象的获取更复杂,程序的复杂度提升,可读性下降。就不应该强行使用设计模式。

给TA打赏
共{{data.count}}人
人已打赏
随笔日记

Unity3D 对象池思想 在游戏开发中的运用

2020-11-9 5:13:30

随笔日记

Asp.net core 简单介绍

2020-11-9 5:13:32

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索