一文带你了解Java创建型设计模式之原型模式

目录
  • 原型模式
    • 概述
    • 优缺点
    • 应用场景
    • 主要角色
  • 原型模式的基本使用
    • 创建原型接口
    • 创建具体需要克隆对象
    • 使用
  • JDK自带原型接口的使用
  • 浅克隆与深度克隆
    • 浅克隆
    • 深度克隆
  • 单例的破坏

原型模式

概述

原型模式(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原型模式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 深入理解Java设计模式之原型模式

    目录 一.前言 二.什么是原型模式 三.原型模式的适用场景 四.原型模式的实现 1.浅拷贝实现 2.深拷贝实现 五.总结 一.前言 单例模式可以避免重复创建消耗资源的对象,但是却不得不共用对象.若是对象本身也不让随意访问修改时,怎么办?通常做法是备份到副本,其它对象操作副本,最后获取权限合并,类似git上的PR操作. 二.什么是原型模式 原型模式用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.需要注意的关键字是,新的对象,类没变..NET在System命名空间中提供了Cloneab

  • 一文带你了解Java设计模式之原型模式

    目录 定义 解决的问题 核心要点 类图 浅复制与深复制的区别 代码实现 未使用设计模式 实现Cloneable接口 深复制-重写clone 深复制-通过对象序列化实现(推荐) 拓展 定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型模式其实就是从一个对象在创建另外一个可定制的对象,不需要知道任何创建的细节 解决的问题 在运行期建立和删除原型. 经常用于: 类初始化消耗资源较多 构造函数比较复杂 核心要点 1.实现cloneable 接口,重写Object的clone方法

  • Java 深入理解创建型设计模式之原型模式

    1.思考问题 现在有一只羊 tom,姓名为: tom,年龄为:1,颜色为:白色,请编写程序创建和 tom羊属性完全相同的10只羊. 按照传统的思路来,我们可能会按照下面的方式去写. 那么这种写法的优缺点自然而然就出来了: 优点是比较好理解,简单易操作. 缺点是在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低.总是需要重新初始化对象,而不是动态地获得对象运行时的状态,不够灵活. 改进的思路分析:Java中Object类是所有类的根类,Object类提供了一个 c

  • java设计模式--原型模式详解

    目录 引例 原型模式 浅拷贝 在原先Sheep类基础上实现Cloneable接口,重写clone方法. 客户端调用 Sheep类 新添的Cow类 客户端调用克隆 深拷贝 1.Cow类也实现Cloneable接口 Sheep类的clone再添加调用cow的clone 客户端调用 1.Cow类实现序列化接口,不必实现Cloneable接口了 2.在Sheep类实现序列化接口 3.客户端调用 总结 引例 问题: 现在有一只羊(包含属性:名字Dolly.年龄2),需要克隆10只属性完全相同的羊. 一般解

  • Java 深入探讨设计模式之原型模式篇

    目录 传统方式 原型模式基本介绍 原型模式在spring框架中源码分析 深入讨论-浅讨论和深拷贝 原型模式的注意事项和细节 传统方式 克隆羊问题 现在有一只羊 tom,姓名为: tom,年龄为:1,颜色为:白色,请编写程序创建和 tom羊属性完全相同的10只羊. 传统方式解决克隆羊问题 思路分析(图解) 代码演示: public class Sheep { private String name; private int age; private String color; public She

  • Java设计模式之java原型模式详解

    目录 介绍 角色 Java语言提供的clone()方法 代码演示-克隆羊 结论 深浅拷贝 深浅拷贝探讨 实现深克隆的方式一 : 手动对引用对象进行克隆 实现深克隆的方式一 :序列化 原型模式对单例模式的破坏 优缺点 适用场景 原型模式在Spring中的应用场景 总结 介绍 原型模式(Prototype Pattern):使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.原型模式是一种对象创建型模式. 原型模式的工作原理很简单:将一个原型对象传给那个要发动创建的对象,这个要发动创建

  • Java设计模式之原型模式的示例详解

    目录 定义 案例 需求 方案一 方案二 对比分析 总结 定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 即实现了一个原型接口,该接口用于创建当前对象的克隆,当直接创建对象的代价比较大时,则采用这种模式 案例 需求 张三要打印100000份照片 方案一 定义照片类 /** * 照片类 * @author:liyajie * @createTime:2022/2/15 11:47 * @version:1.0 */ @Data @AllArgsConstructor publi

  • Java 设计模式以虹猫蓝兔的故事讲解原型模式

    目录 什么是原型模式 优点 缺点 应用场景 浅克隆 代码实现 总结 深克隆 代码实现 总结 什么是原型模式 原型(Prototype)模式的定义如下: 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象.在这里,原型实例指定了要创建的对象的种类.用这种方式创建对象非常高效,根本无须知道对象创建的细节.例如,Windows 操作系统的安装通常较耗时,如果复制就快了很多.在生活中复制的例子非常多,这里不一一列举了. 优点 1.Java 自带的原型模式基于内存二进制流的

  • Java 深入理解创建型设计模式之建造者模式

    1.提出问题 假如说,我们需要建房子:这一过程为打桩.砌墙.封顶.房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不要相同的.3)请编写程序,完成需求. 传统的想法应该就是下面这个类图的形式.. 那么这种写法的优点就是 比较好理解,简单易操作. 缺点则是:设计的程序结构,过于简单,没有设计缓存层对象,程序的扩展和维护不好.也就是说,这种设计方案,把产品(即: 房子)和创建产品的过程(即: 建房子流程)封装在一起,耦合性增强了. 解决方案:  将产品和产品建造过程解耦 

  • java编程创建型设计模式工厂方法模式示例详解

    目录 1.什么是工厂方法模式? 2.案例实现 3.JDK中的工厂方法模式 1.什么是工厂方法模式? 工厂方法模式设计方案:  将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现. 工厂方法模式:  定义了一个创建对象的抽象方法,由子类决定要实例化的类.工厂方法模式将对象的实例化推迟到子类. 何时使用?  不同条件下创建不用实例时.方法是让子类实现工厂接口. 2.案例实现 假如说,我们现在有这样一个需求:客户在点披萨时,可以点不同口味的披萨,比如北京的奶酪pizza.北京的胡椒p

  • Java创建型设计模式之工厂方法模式深入详解

    目录 简单工厂模式 定义产品对象 创建工厂类 工厂使用反射 工厂方法模式 概述 应用场景 优缺点 主要角色 工厂方法模式的基本使用 创建抽象产品 创建具体产品 创建抽象工厂 创建具体工厂 客户端执行 简单工厂模式 简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类的实例,但是它不属于设计模式. 简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心. 定义产品对象 public interf

  • Java创建型设计模式之抽象工厂模式(Abstract Factory)

    目录 抽象工厂模式 概述 产品等级结构与产品族 优缺点 主要角色 抽象工厂模式的基本使用 创建抽象产品 创建具体产品 创建抽象工厂 创建具体工厂 客户端执行 抽象工厂模式 概述 抽象工厂模式(Abastract Factory Pattern)属于创建型模式,它提供了一种创建对象的最佳方式. 它提供一个创建一系列相关或相互依赖对象的接口,无须显式指定他们具体的类.每个生成的工厂都能按照工厂模式提供对象. 抽象工厂模式是围绕一个超级工厂创建其他工厂,该超级工厂又称为其他工厂的工厂. 产品等级结构与

  • 深入了解Java行为型设计模式之策略模式

    目录 策略模式 应用场景 优缺点 主要角色 策略模式的基本使用 创建抽象策略角色 创建具体策略角色 创建上下文角色 客户端执行 策略模式实现支付方式的选择 创建抽象策略角色 创建具体策略角色 创建上下文角色 客户端执行 策略模式 策略模式(Strategy Pattern)也叫政策模式(Policy Pattern),属于行为型模式. 它是将定义的一系列算法.分别封装起来,让它们之间可以互相替换,从而让算法的变化不会影响到使用算法的用户. 策略模式能让你定义一系列算法, 并将每种算法分别放入独立

  • Java行为型设计模式之策略模式详解

    目录 1.策略设计模式定义 2.策略设计模式的有点与不足 3.策略设计模式的实现思路 4.代码示例 5.策略设计模式的应用场景 编程是一门艺术,大批量的改动显然是非常丑陋的做法,用心的琢磨写的代码让它变的更美观. 在现实生活中常常遇到实现某种目标存在多种策略可供选择的情况,例如超市促销可以釆用打折.送商品.送积分等方法. 在软件开发中也常常遇到类似的情况,当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有快速排序.归并排序.选

  • java编程创建型设计模式单例模式的七种示例

    目录 1.什么是单例模式? 2.七种写法 2.1饿汉式(静态常量) 2.2饿汉式(静态代码块) 2.3懒汉式(线程不安全) 2.4懒汉式(线程安全,同步方法) 2.5双重校验锁 2.6静态内部类 2.7枚举 3.单例模式在JDK中的应用(简单的源码分析) 4.单例模式总结 1.什么是单例模式? 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法). 比如Hibernate的 SessionFactory,

随机推荐