java设计模式 - 原型(干货)

 深度讲解23种设计模式,力争每种设计模式都刨析到底。废话不多说,开始第二种设计模式 - 原型。

一、为什么有原型模式

 当一个类需要克隆的时候,我们总不希望new一个对象,然后逐个属性去设置值。 这个时候,我们亟需一种

高效的对象copy方法,原型设计模式应运而生。

二、原型设计模式写法

 原型设计模式实现:

public class Person implements Cloneable {

    private String userName;

    private String sex;

    private int age;

    public String getUserName() {        return userName;    }

    public void setUserName(String userName) {        this.userName = userName;    }

    public String getSex() {        return sex;    }

    public void setSex(String sex) {        this.sex = sex;    }

    public int getAge() {        return age;    }

    public void setAge(int age) {        this.age = age;    }

    @Override    protected Person clone() throws CloneNotSupportedException {        Person person = (Person) super.clone();        return person;    }

    @Override    public String toString() {        return "Person{" +                "userName=‘" + userName + ‘\‘‘ +                ", sex=‘" + sex + ‘\‘‘ +                ", age=" + age +                ‘}‘;    }}
public static void main(String[] args) throws CloneNotSupportedException {    Person p = new Person();    p.setAge(19);    p.setUserName("小明");    p.setSex("男");    Person p1 = p.clone();

    System.out.println(p.hashCode());    System.out.println(p1.hashCode());

    p.setAge(12);

    System.out.println(p);    System.out.println(p1);}执行结果

  

 原型实现,在Person类中,实现了Cloneable 接口,然后重写clone方法,即可。

 一切看似都很美好,然而,如果在Person中增加一个不是基本类型,也不是String类型的属性时,情况会令你意外。

 1,浅拷贝

public class Person implements Cloneable {

    private String userName;

    private String sex;

    private int age;

    private Son son;

    public Son getSon() {        return son;    }

    public void setSon(Son son) {        this.son = son;    }

    public String getUserName() {        return userName;    }

    public void setUserName(String userName) {        this.userName = userName;    }

    public String getSex() {        return sex;    }

    public void setSex(String sex) {        this.sex = sex;    }

    public int getAge() {        return age;    }

    public void setAge(int age) {        this.age = age;    }

    @Override    protected Person clone() throws CloneNotSupportedException {        Person person = (Person) super.clone();        return person;    }

    @Override    public String toString() {        return "Person{" +                "userName=‘" + userName + ‘\‘‘ +                ", sex=‘" + sex + ‘\‘‘ +                ", age=" + age +                ", son=" + son +                ‘}‘;    }}
public class Son {

    private String sonName;

    public String getSonName() {        return sonName;    }

    public void setSonName(String sonName) {        this.sonName = sonName;    }

    @Override    public String toString() {        return "Son{" +                "sonName=‘" + sonName + ‘\‘‘ +                ‘}‘;    }}
public class Test {    public static void main(String[] args) throws CloneNotSupportedException {        Person p = new Person();        p.setAge(19);        p.setUserName("小明");        p.setSex("男");        Son son = new Son();        son.setSonName("小明的孩子");        p.setSon(son);        Person p1 = p.clone();

        System.out.println(p.hashCode());        System.out.println(p1.hashCode());

        p1.getSon().setSonName("隔壁老王的孩子");        p1.setAge(12);

        System.out.println(p);        System.out.println(p1);    }}运行结果如下

  

 那么为什么能够出现这样的结果呢?

 因为clone方法并不能穿透到son,也就是p和p1公用了son对象(p1对象对son的clone只是copy了指针,并没有完全copy,也就是浅拷贝),所以p和p1同时输出的“隔壁老王的孩子”。

 

 如果我们希望实现完整的clone,该如何处理呢?我们需要深拷贝。

 2,深拷贝

  1)套娃式深拷贝

  我们在浅拷贝的基础上修改,修改部分笔者用红色标识。

public class Person implements Cloneable {

    private String userName;

    private String sex;

    private int age;

    private Son son;

    public Son getSon() {        return son;    }

    public void setSon(Son son) {        this.son = son;    }

    public String getUserName() {        return userName;    }

    public void setUserName(String userName) {        this.userName = userName;    }

    public String getSex() {        return sex;    }

    public void setSex(String sex) {        this.sex = sex;    }

    public int getAge() {        return age;    }

    public void setAge(int age) {        this.age = age;    }

    @Override    protected Person clone() throws CloneNotSupportedException {        Person person = (Person) super.clone();        person.setSon(person.getSon().clone());        return person;    }

    @Override    public String toString() {        return "Person{" +                "userName=‘" + userName + ‘\‘‘ +                ", sex=‘" + sex + ‘\‘‘ +                ", age=" + age +                ", son=" + son +                ‘}‘;    }}
public class Son implements Cloneable {

    private String sonName;

    public String getSonName() {        return sonName;    }

    public void setSonName(String sonName) {        this.sonName = sonName;    }

    @Override    public String toString() {        return "Son{" +                "sonName=‘" + sonName + ‘\‘‘ +                ‘}‘;    }

    @Override    protected Son clone() throws CloneNotSupportedException {        return (Son) super.clone();    }}我们再来看结果:

  

  很显然,得到了我们期望的结果,像不像套娃?

  2)序列化深拷贝

  首先改造Person

public class Person implements Serializable {

    private String userName;

    private String sex;

    private int age;

    private Son son;

    public Son getSon() {        return son;    }

    public void setSon(Son son) {        this.son = son;    }

    public String getUserName() {        return userName;    }

    public void setUserName(String userName) {        this.userName = userName;    }

    public String getSex() {        return sex;    }

    public void setSex(String sex) {        this.sex = sex;    }

    public int getAge() {        return age;    }

    public void setAge(int age) {        this.age = age;    }

    @Override    public String toString() {        return "Person{" +                "userName=‘" + userName + ‘\‘‘ +                ", sex=‘" + sex + ‘\‘‘ +                ", age=" + age +                ", son=" + son +                ‘}‘;    }}接着,改造Son
public class Son implements Serializable {

    private String sonName;

    public String getSonName() {        return sonName;    }

    public void setSonName(String sonName) {        this.sonName = sonName;    }

    @Override    public String toString() {        return "Son{" +                "sonName=‘" + sonName + ‘\‘‘ +                ‘}‘;    }

}Main方法
public class Test {    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {        Person p = new Person();        p.setAge(19);        p.setUserName("小明");        p.setSex("男");        Son son = new Son();        son.setSonName("小明的孩子");        p.setSon(son);

        ByteArrayOutputStream bos=new ByteArrayOutputStream();        ObjectOutputStream oos=new ObjectOutputStream(bos);        oos.writeObject(p);

        ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());        ObjectInputStream ois=new ObjectInputStream(bis);        Person p1= (Person) ois.readObject();

        System.out.println(p.hashCode());        System.out.println(p1.hashCode());

        p1.getSon().setSonName("隔壁老王的孩子");        p1.setAge(12);

        System.out.println(p);        System.out.println(p1);    }}来看看输出结果:

  

 很显然,得到了我们期望的结果。

 当然,可以把序列化过程封装到Person中。没有了套娃,又可以欢乐玩耍了。

 总结:每一种拷贝都有自己的应用场景,要看具体的业务场景。

原文地址:https://www.cnblogs.com/x-j-p/p/12381088.html

时间: 2024-10-15 19:38:03

java设计模式 - 原型(干货)的相关文章

Java设计模式——原型模式

概述 原型模式是为了解决一些不必要的对象创建过程.当Java JDK中提供了Cloneable接口之后,原型模式就变得异常的简单了.虽然由于Cloneable的引入使用程序变得更简单了,不过还是有一些需要说明和注意的东西在里面的.文本就详细讲解一下这些注意事项吧. 版权说明 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:Coding-Naga发表日期: 2016年3月3日链接:http://blog.csdn.net/lemon_tree12138/article/d

java设计模式---原型模式

原型模式也是创建型的设计模式,通过拷贝原型创建新的对象,理解原型模式必须理解java中的浅复制和深复制.复制也称为克隆.会发生深拷贝的有java中的8中基本类型以及他们的封装类型,另外还有String类型.其余的都是浅拷贝. 浅克隆:浅克隆仅仅克隆所考虑的对象,而不克隆它所引用的对象. 深克隆:深克隆不仅克隆所考虑的对象,也克隆它所引用的对象. 它的核心是就是原型类Prototype.Prototype类需要具备以下两个条件: 实现Cloneable接口.在java语言有一个Cloneable接

JAVA 设计模式 原型模式

用途 原型模式 (Prototype) 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型模式是一种创建型模式. 结构 图-原型模式结构图 Prototype: 声明一个克隆自身的接口.ConcretePrototype: 实现克隆自身的具体操作.Client: 调用 Prototype 来克隆自身,从而创建一个新对象. 应用场景 当要实例化的类是在运行时刻指定时,例如,通过动态装载.为了避免创建一个与产品类层次平行的工厂类层次时.当一个类的实例只能有几个不同状态组合中的一种

Java 设计模式——原型模式(Prototype)

原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象. 原型模式有简单形式和登机形式两种表现 形式. 简单形式的原始模型模式 简单形式UML类图如下: 原型模式的角色有 客户端角色(ClientPro): 抽象原型角色(ProtoType): 具体原型角色(ConcreteProtoType):被复制的对象 代码如下: public interface ProtoType { /** * 根据自身克隆出新的对象 * @aut

java设计模式-原型(prototype)

有时候创建对象是需要耗费很多资源,但是每个对象之间又有大量的重复.我们可以选择在创建好一个对象后,以之作为模板克隆出其他对象,稍作修改,即可用于其他地方. 需要实现Cloneable接口,重写clone()方法.其实就是调用的Object类的clone()方法. 克隆对象只是复制了原对象的数据,每个对象还是独立的,他们的内存地址不同. /** * Created by wangbin10 on 2018/5/18. */ public class Prototype2 implements Cl

Java设计模式(三)原型模式

(五)原型模式 Prototype 原型模式目的是复制一个现有对象来生成新的对象,而不是通过实例化的方式.原型模式需要实现 Cloneable 接口,覆写clone方法,复制分为浅复制.深复制. 浅复制:将一个对象复制后,基本数据类型的变量都重新创建,引用类型,指向的还是原对象所指向的. 深复制:讲一个对象复制后,不论基本数据类型和引用类型,都是重新创建,是完全的彻底的复制. public class ProtoType { public static void main(String[] ar

《Java设计模式》之原型模式

原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象.这就是原型模式的用意. 原型模式的结构 原型模式要求对象实现一个可以"克隆"自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例.这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再去通过new来创建. 原型模式有两种表现形式:(1)简单形式.(2)登记形式,这两

图解Java设计模式之原型模式

图解Java设计模式之原型模式 克隆羊的问题 原型模式 - 基本介绍 原型模式在Spring框架中源码分析 浅拷贝的介绍 深拷贝基本介绍 克隆羊的问题 现在有一只羊tom,姓名为 : tom,年龄为 :1,颜色为 :白色,请编写程序创建和tom羊属性完全相同的10只羊. 传统方式解决克隆羊的问题 package com.example.demo.prototype; public class Sheep { private String name; private int age; privat

JAVA设计模式之 原型模式【Prototype Pattern】

一.概述: 使用原型实例指定创建对象的种类,而且通过拷贝这些原型创建新的对象. 简单的说就是对象的拷贝生成新的对象(对象的克隆),原型模式是一种对象创建型模式. 二.使用场景: 创建新的对象能够通过对已有对象进行复制来获得,假设是相似对象,则仅仅需对其成员变量稍作改动. 三.UML结构图: 四.參与者 (1)    Prototype(抽象原型类):它是声明克隆方法的接口,是全部详细原型类的公共父类,能够是抽象类也能够是接口,甚至还能够是详细实现类. (2)    ConcretePrototy