原型模式

概述

原型模式(Prototype Pattern)是属于创建型模式。

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

原型模式的核心在于拷贝原型对象。以存在的一个对象为原型,直接基于内存二进制流进行拷贝,无需再经历耗时的对象初始化过程(不调用构造函数),性能提升许多。

当直接创建对象的代价比较大时,则采用这种模式。利用当前系统中已存在的对象作为原型,对其进行克隆,避免初始化的过程。

优缺点

优点:

1.java自带的原型模式是基于内存二进制流的拷贝,比直接new一个对象性能上提升许多

2.使用原型模式将对象复制一份并将其状态保存起来,简化创建对象的过程,以便在需要的时候使用

缺点:

1.需要为每一个类配置一个克隆方法

2克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反开闭原测

3.在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支特深克隆,实现比较麻烦

应用场景

1.类初始化消耗资源较多

2.new产生的一个对象需要非常繁琐的过程(数据准备或访问权限)

3.构造函数处比较复杂

4.循环体中生产大量对象时

5.资源优化场景

6.性能和安全要求的场景

主要角色

1.客户(Client)角色

客户端类向原型管理器提出创建对象的请求。

2.抽象原型(Prototype)角色

这是一个抽象角色,此角色给出所有的具体原型类所需的接口。

3.具体原型(Concrete Prototype)角色

被复制的对象。此角色需要实现抽象的原型角色所要求的接口。

4.原型管理器(Prototype Manager)角色

创建具体原型类的对象,并记录每一个被创建的对象。

原型模式的基本使用

创建原型接口

public interface IPrototype<T> {
    T clone();
}

创建具体需要克隆对象

@Data
@ToString
public class ConcretePrototype implements IPrototype {
    private int age;
    private String name;
    @Override
    public ConcretePrototype clone() {
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setAge(this.age);
        concretePrototype.setName(this.name);
        return concretePrototype;
    }
}

使用

    public static void main(String[] args) {
        //创建原型对象
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(20);
        prototype.setName("jack");
        System.out.println(prototype);
        //拷贝原型对象
        ConcretePrototype cloneType = prototype.clone();
        System.out.println(cloneType);
    }

JDK自带原型接口的使用

原型模式就是如此简单,通常开发中不会这样使用。其实JDK提供了一个现成的API接口,那就是Cloneable接口。

@Data
@ToString
public class ConcretePrototype implements Cloneable {
    private int age;
    private String name;
    private List<String> hobbies;
    @Override
    public ConcretePrototype clone() {
        try {
            return (ConcretePrototype)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

浅克隆与深度克隆

浅克隆

添加一个hobby属性,当给克隆对象的hobby属性添加一项时,最终结果会导致原型对象发生变化,也就是hobby属性用于一个内存地址。这就是浅克隆。

@Data
@ToString
public class ConcretePrototype implements Cloneable {
    private int age;
    private String name;
    private List<String> hobby;
    @Override
    public ConcretePrototype clone() {
        try {
            return (ConcretePrototype)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}
    public static void main(String[] args) {
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(22);
        prototype.setName("jack");
        List<String> hobby = new ArrayList<String>();
        hobby.add("java");
        hobby.add("python");
        hobby.add("go");
        prototype.setHobby(hobby);
        // 拷贝原型对象
        ConcretePrototype cloneType = prototype.clone();
        cloneType.getHobby().add("php");
        System.out.println("原型对象:"   prototype);
        System.out.println("克隆对象:"   cloneType);
        System.out.println(prototype == cloneType);
        System.out.println(prototype.getHobby() == cloneType.getHobby());
    }

原型对象:ConcretePrototype(age=22, name=jack, hobby=[java, python, go, php])
克隆对象:ConcretePrototype(age=22, name=jack, hobby=[java, python, go, php])
false
true

深度克隆

可使用序列化方式实现对象的深度克隆

@Data
@ToString
public class ConcretePrototype implements Cloneable, Serializable {
    private int age;
    private String name;
    private List<String> hobby;
    @Override
    public ConcretePrototype clone() {
        try {
            return (ConcretePrototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
    public ConcretePrototype deepClone() {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return (ConcretePrototype) ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
    public static void main(String[] args) {
        //创建原型对象
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(22);
        prototype.setName("jack");
        List<String> hobby = new ArrayList<String>();
        hobby.add("java");
        hobby.add("python");
        hobby.add("go");
        prototype.setHobby(hobby);
        // 拷贝原型对象
        ConcretePrototype cloneType = prototype.deepClone();
        cloneType.getHobby().add("php");
        System.out.println("原型对象:"   prototype);
        System.out.println("克隆对象:"   cloneType);
        System.out.println(prototype == cloneType);
        System.out.println(prototype.getHobby() == cloneType.getHobby());
    }

原型对象:ConcretePrototype(age=22, name=jack, hobby=[java, python, go])
克隆对象:ConcretePrototype(age=22, name=jack, hobby=[java, python, go, php])
false
false

也可这样操作,多克隆一次

    public ConcretePrototype deepClone2() {
        try {
            ConcretePrototype result = (ConcretePrototype) super.clone();
            result.hobby = (List) ((ArrayList) result.hobby).clone();
            return result;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

单例的破坏

如果克隆的目标对象是单例对象,深克隆就会破坏单例。

解决方案:禁止深克隆。

1.让单例类不实现Cloneable接口

2.重写clone方法,在clone方法中返回单例对象即可

@Data
@ToString
public class ConcretePrototype implements Cloneable {
    private static  ConcretePrototype instance = new ConcretePrototype();
    private ConcretePrototype(){}
    public static ConcretePrototype getInstance(){
        return instance;
    }
    @Override
    public ConcretePrototype clone() {
       return instance;
    }
}

到此这篇关于一文带你了解Java创建型设计模式之原型模式的文章就介绍到这了,更多相关Java原型模式内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

一文带你了解Java创建型设计模式之原型模式的更多相关文章

  1. Swift设计模式之原型模式

    转自Swift设计模式原文Design-Patterns-In-Swift

  2. MVVM 不是那么好

    我觉得MVVM是一种反人类的设计模式,它使架构更加混乱而非清晰。MVVM命名很糟糕名称是很重要的。ViewModel这一名称则没有发挥任何作用。ViewModel的第一种含义是modelfortheview。MVVM引进太多职责命名不够具体,导致这个类的任务无休止地增长。MVVM不改变你的架构viewmodel并不能从根本上改变你的应用程序的架构。我能想到的MVVM模式最大的好处就是它把“下水道”从苹果自带的viewcontrooller类转移到了viewmodel这一自定义的对象。

  3. swift设计模式学习 - 原型模式

    原型模式的基本实现上图是最基本的原型模式的结构图,下面将用Swift代码来实现一个基本原型模式:不知道大家有没哟发现,这个设计模式我们在代码中经常会用到,那就是NScopying协议,通过这个协议来实现对象的深拷贝,下面我们就用NScopying来实现一下。原型模式解决实际问题上面是通过NScopying来实现原型模式的例子,一下是使用过程:以下是打印的结果:以上是我对于原型模式的理解,如果有不对的地方欢迎大家交流,最后谢谢大家的阅读~~

  4. swift-原型模式

    GoF提出了23种设计模式,本系列将使用Swift语言来实现这些设计模式。概述通过复制一个已存在的对象来获得一个新的相同类型的对象被称作原型模式,在复制的过程中不需要关心被复制对象实现的接口或者类型。,pet:Pet))}简单形式拷贝通过声明一个cloning协议来为需求方提供完全拷贝的方案123456789101112131415161718protocolcloning{funcclone()->AnyObject}classpet:NSObject,cloning{funcclone()->AnyO

  5. 开发Swift iOS应用程序“正确的方式”

    最近,我学习了Swift和开发iOS应用程序的基础知识。现在,我想自己开发一个真正的应用程序,但我非常关心编写好的代码,所以我已经寻找“最佳实践”,“设计模式”和“正确的方式”来实现它。在我的搜索中,我发现这个greattutorial关于SwiftiOS应用程序中通常使用的所有设计模式,以及他们使用的示例。不应该将httpClient和persistencyManager声明为协议,然后HttpClient和PersistencyManager类实现该协议?我应该在哪里告诉应用程序?最后但并非最不重要的

  6. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  7. javascript的23种设计模式示例总结大全

    这篇文章主要为大家介绍了javascript的23种设计模式的总结大全,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  8. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  9. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  10. 详解JavaScript实现设计模式中的适配器模式的方法

    适配器模式可以根据需求转换(或调整)一个接口,创建含有您所需接口的另一个对象,并将它连接到您想改变接口的对象,从而完成这种转换,下面就来详解JavaScript实现设计模式中的适配器模式的方法

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部