资讯专栏INFORMATION COLUMN

设计模式之原型模式

jsyzchen / 416人阅读

摘要:但是这种复制技术在的世界里早已出现,就是原型模式什么是原型模式用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象类图原型模式是设计模式中最简单的,没有之一。

前言

在现实世界中,我们通常会感觉到分身乏术。要是自己有分身那该多好啊,一个用来工作,一个用来看电视,一个用来玩游戏(无意中透露了自己单身狗的身份-。-),其实就是克隆,这种技术存在着很大的弊端,所以现在是禁止使用的。但是这种复制技术在java的世界里早已出现,就是原型模式

什么是原型模式

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

uml类图

原型模式是设计模式中最简单的,没有之一。因为它的核心就是一个clone方法,通过这个方法完成对象的克隆。java提供了cloneable接口来标示这个对象是有可能被克隆的,这个接口只具有标记作用,在jvm中只有具有这个标记的对象才有可能被克隆。有可能克隆变成可以被克隆,就需要我们重写clone方法

浅拷贝
public class Person implements Cloneable{

    public Person() {
        System.out.println("构造函数执行了");
    }

    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    protected Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }
}
public class Client {

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.setName("bin");

        Person person1=person.clone();
        person1.setName("123");
        System.out.println(person.getName()+"---"+person1.getName());
    }
}
测试结果:
构造函数执行了
bin---123

通过以上例子可以得知,实现cloneable接口,复写clone方法,即可对对象进行复制。有一个问题clone方法是怎么创建对象的?可以看到,构造函数只执行了一次,这就说明clone方法是不会调用构造函数的,它其实是内存二进制流的拷贝,比直接new对象性能要好很多。
标题是浅拷贝,那到底什么是浅拷贝呢?先不要着急,我们来改动下例子:

public class Person implements Cloneable{

    private List valueList = new ArrayList<>();

    public void setValue(){
        valueList.add("1");
    }
    public List getValue(){
        return valueList;
    }
    
    @Override
    protected Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }
}
public class Client {

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.setValue();

        Person person1=person.clone();
        person1.setValue();
        System.out.println(person1.getValue());
    }
}
测试过程:
构造函数执行了
[1, 1]

或许你会很费解明明进行了拷贝,应该只会打印一个“1”啊,,为什么person1.getValue()会打印出两个“1”呢?因为java做了一个偷懒的拷贝动作,Object提供的clone方法只拷贝本对象,对其引用对象和内部数组都不拷贝,只是将地址拷贝过来用,这种拷贝方式就是浅拷贝。但是String对象例外,因为java本就希望将String看成基本数据类型,它没有clone方法,并且它的处理机制非常特殊,通过字符串池在内存中创建新的字符串,我们只要把其看待成基本数据类型就可以了。

深拷贝

当拷贝的对象中有引用对象或者数组时,我们通过浅拷贝获得复制对象是不安全的。怎么解决呢?我们可以通过深拷贝来解决这个问题,下面继续改造例子学习深拷贝:

public class Person implements Cloneable{

    private ArrayList valueList = new ArrayList<>();

    public void setValue(){
        valueList.add("1");
    }
    public List getValue(){
        return valueList;
    }

    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person=(Person) super.clone();
        person.valueList= (ArrayList) this.valueList.clone();
        return person;
    }
}
public class Client {

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.setValue();

        Person person1=person.clone();
        person1.setValue();
        System.out.println(person.getValue());
        System.out.println(person1.getValue());
    }
}
测试结果:
person:[1]
person1[1, 1]

通过对引用对象和数组的进行独立的拷贝,就完成了深拷贝,每个person对象都会有自己的valueList。

clone和final

对象的clone和对象内的final是互相冲突的,下面我们来看个图片:


当我们将valueList增加final关键字,对其clone编译会报错,解决办法就是不要加final关键字(感觉像是废话...)

总结

原型模式和现实世界中说的克隆基本一样。原型模式是内存二进制流的拷贝,比new对象性能高很多,尤其是当创建这个对象需要数据库或者其他硬件资源时尤为明显。另外我们需要注意的就是当复制的对象存在引用对象和数组时,要根据实际业务选择深拷贝还是浅拷贝。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70834.html

相关文章

  • #yyds干货盘点#Java设计模式(四)——原型模式

    摘要:如果一个对象的初始化需要很多其他对象的数据准备或其他资源的繁琐计算,那么可以使用原型模式。当需要一个对象的大量公共信息,少量字段进行个性化设置的时候,也可以使用原型模式拷贝出现有对象的副本进行加工处理。 1、什么是原型模式Specify the kinds of objects to create using a prot...

    番茄西红柿 评论0 收藏2637
  • 《javascript高级程序设计》第六章 读书笔记 javascript对象的几种创建方式

    摘要:三种使用构造函数创建对象的方法和的作用都是在某个特殊对象的作用域中调用函数。这种方式还支持向构造函数传递参数。叫法上把函数叫做构造函数,其他无区别适用情境可以在特殊的情况下用来为对象创建构造函数。 一、工厂模式 工厂模式:使用字面量和object构造函数会有很多重复代码,在此基础上改进showImg(https://segmentfault.com/img/bVbmKxb?w=456&...

    xiaotianyi 评论0 收藏0
  • 优才公开课笔记:php设计模式 (四)原型模式

    摘要:继续分享设计模式的公开课,这是第四篇创建型模式之原型模式设计模式的一般介绍在第一篇文章讲了,不了解的可以先看看。设计模式的第一部分,创建型模式就总结完了。下面还有两部分结构型设计模式和行为型设计模式稍后继续。 继续分享设计模式的公开课,这是第四篇创建型模式之原型模式 设计模式的一般介绍在第一篇文章讲了,不了解的可以先看看。 原型模式: 用原型实例指定创建对象的种类,并且通过拷贝这个...

    Maxiye 评论0 收藏0
  • 面向对象的程序设计原型模式

    摘要:可以用删除实例对象中自己添加的属性可以确定属性是原型中还是实例对象中,当时实例对象中时,返回的是操作符,有两种使用方式,单独使用和循环中。单独使用,通过对象能够访问属性时返回,无论时在原型中还是实例对象中。 原型模式,每个创建的对象都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。 ------------...

    yunhao 评论0 收藏0
  • JavaScript深入创建对象的多种方式以及优缺点

    摘要:深入系列第十四篇,讲解创建对象的各种方式,以及优缺点。也就是说打着构造函数的幌子挂羊头卖狗肉,你看创建的实例使用都无法指向构造函数这样方法可以在特殊情况下使用。 JavaScript深入系列第十四篇,讲解创建对象的各种方式,以及优缺点。 写在前面 这篇文章讲解创建对象的各种方式,以及优缺点。 但是注意: 这篇文章更像是笔记,因为《JavaScript高级程序设计》写得真是太好了! 1....

    Terry_Tai 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<