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

目录
  • 定义
    • 解决的问题
    • 核心要点
    • 类图
    • 浅复制与深复制的区别
  • 代码实现
    • 未使用设计模式
    • 实现Cloneable接口
    • 深复制-重写clone
    • 深复制-通过对象序列化实现(推荐)
  • 拓展

定义

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

原型模式其实就是从一个对象在创建另外一个可定制的对象,不需要知道任何创建的细节

解决的问题

在运行期建立和删除原型。

经常用于:

类初始化消耗资源较多

构造函数比较复杂

核心要点

1.实现cloneable 接口,重写Object的clone方法

2.利用已有的一个原型对象,快速地生成和原型对象一样的实例。

类图

浅复制与深复制的区别

浅复制:基本数据类型进行值传递、引用数据类型的指针仍是指向原来的对象(成员变量)。

深复制:基本数据类型进行值传递、引用数据类型开辟新的内存空间。

代码实现

需求:实现克隆羊

有一头羊,需要经过赋值再克隆出两头。

未使用设计模式

/**
 * 克隆羊类
 *
 * @author Promsing(张有博)
 * @version 1.0.0
 * @since 2022/9/3 - 14:51
 */
public class Sheep {

    private String name;

    private Integer age;

    private String color;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public String getColor() {
        return color;
    }

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

    public Sheep() {
    }

    public Sheep(String name, Integer age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }
}

Main方法

/**
 *
 * 传统模式
 * @author Promsing(张有博)
 * @version 1.0.0
 * @since 2022/9/3 - 14:47
 */
public class Client {

    public static void main(String[] args) {
        //小羊
        Sheep sheep=new Sheep("小红",8,"红色");
        //克隆羊
        Sheep sheep2=sheep;
        Sheep sheep3=sheep;

        System.out.println("通过赋值,指针还是指向sheep");
        System.out.println(sheep);
        System.out.println(sheep2);
        System.out.println(sheep3);

    }

}

//通过赋值,指针还是指向sheep
//com.promsing.creational.prototype.type1.Sheep@1b6d3586
//com.promsing.creational.prototype.type1.Sheep@1b6d3586
//com.promsing.creational.prototype.type1.Sheep@1b6d3586

实现Cloneable接口

Cloneable是标记型的接口,它们内部都没有方法和属性,实现 Cloneable来表示该对象能被克隆,能使用Object.clone()方法。

如果没有实现 Cloneable的类对象调用clone()就会抛出CloneNotSupportedException。

实现Cloneable默认是浅复制

/**
 * 克隆羊
 *
 * @author Promsing(张有博)
 * @version 1.0.0
 * @since 2022/9/3 - 14:53
 */
public class Sheep implements Cloneable {

    private String name;

    private Integer age;

    private String color;

    /**
     * 羊的朋友
     */
    private Sheep friend;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public String getColor() {
        return color;
    }

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

    public Sheep() {
    }

    public Sheep getFriend() {
        return friend;
    }

    public void setFriend(Sheep friend) {
        this.friend = friend;
    }

    public Sheep(String name, Integer age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    /**
     * 克隆该实例,调用object.clone的方法
     * @return
     */
    @Override
    protected Sheep clone() {

        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();

        } catch (CloneNotSupportedException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return sheep;
    }
}

Main方法

/**
 * 浅复制:浅复制:基本数据类型进行值传递、引用数据类型的指针仍是指向原来的对象(成员变量)。
 */
public class ShallowClient {

    public static void main(String[] args) {

        Sheep sheep=new Sheep("小红",9,"红色");
        sheep.setFriend(new Sheep("小黑",10,"黑色"));
        Sheep sheep1 = sheep.clone();//开辟了新的空间
        Sheep sheep2 = sheep.clone();

        //浅复制
        System.out.println("原型羊"+sheep);
        System.out.println("克隆羊"+sheep1+"-朋友羊-"+sheep1.getFriend());
        System.out.println("克隆羊"+sheep2+"-朋友羊-"+sheep2.getFriend());

//原型羊com.promsing.creational.prototype.type3.Sheep@1b6d3586
//克隆羊com.promsing.creational.prototype.type3.Sheep@4554617c-朋友羊-com.promsing.creational.prototype.type3.Sheep@74a14482
//克隆羊com.promsing.creational.prototype.type3.Sheep@1540e19d-朋友羊-com.promsing.creational.prototype.type3.Sheep@74a14482

    }

}

一定要实现接口cloneable 否则报错:

Exception in thread "main" java.lang.CloneNotSupportedException: com.promsing.creational.prototype.type4.Sheep
    at java.lang.Object.clone(Native Method)
    at com.promsing.creational.prototype.type4.Sheep.clone(Sheep.java:76)
    at com.promsing.creational.prototype.type4.DeepClient.main(DeepClient.java:14)

深复制-重写clone

羊类、房子类都需要实现Cloneable接口

房子类

/**
 * 房子类
 *
 * @author Promsing(张有博)
 * @version 1.0.0
 * @since 2022/9/3 - 15:27
 */
public class House implements Cloneable {

    //地址
    private String address;

    //尺寸
    private Integer size;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Integer getSize() {
        return size;
    }

    public void setSize(Integer size) {
        this.size = size;
    }

    /**
     * 克隆的方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

羊类

/**
 * 克隆羊-深拷贝
 *
 * @author Promsing(张有博)
 * @version 1.0.0
 * @since 2022/9/3 - 15:26
 */
public class Sheep implements  Cloneable {

    private String name;

    private Integer age;

    private String color;

    /**
     * 羊的房子:引用类型
     */
    private House house;

    public House getHouse() {
        return house;
    }

    public void setHouse(House house) {
        this.house = house;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public String getColor() {
        return color;
    }

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

    public Sheep() {
    }

    public Sheep(String name, Integer age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    /**
     * 克隆该实例,调用object,clone的方法
     *
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {

        //对基本数据类型进行处理
        Sheep deep = null;
        deep = (Sheep) super.clone();

        //对引用类型进行处理
        //进行再次克隆
        House clone = (House) deep.getHouse().clone();
        deep.setHouse(clone);

        return deep;
    }

}

Main

/**
 * 深复制:羊类、房子类都需要重写clone的接口,比较麻烦。不符合开闭
 *
 * @author Promsing(张有博)
 * @version 1.0.0
 * @since 2022/9/3 - 15:38
 */
public class DeepClient {

    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep sheep=new Sheep("黑",90,"heisee");
        sheep.setHouse(new House());
        Sheep clone = (Sheep)sheep.clone();
        System.out.println("原本的对象");
        System.out.println(sheep);
        System.out.println(sheep.getHouse());
        System.out.println("克隆的对象");
        System.out.println(clone);
        System.out.println(clone.getHouse());

        //开辟了新的内存空间
        //原本的对象
        //com.promsing.creational.prototype.type4.Sheep@1b6d3586
        //com.promsing.creational.prototype.type4.House@4554617c
        //克隆的对象
        //com.promsing.creational.prototype.type4.Sheep@74a14482
        //com.promsing.creational.prototype.type4.House@1540e19d
    }

}

深复制-通过对象序列化实现(推荐)

羊类、房子类都需要实现Serializable接口。注意这里可以不实现Cloneable了。

房子类

/**
 * 房子类
 *
 * @author Promsing(张有博)
 * @version 1.0.0
 * @since 2022/9/3 - 15:27
 */
public class House implements Serializable{

    //地址
    private String address;

    //尺寸
    private Integer size;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Integer getSize() {
        return size;
    }

    public void setSize(Integer size) {
        this.size = size;
    }

}

羊类

/**
 * 克隆羊-深拷贝
 *
 * @author Promsing(张有博)
 * @version 1.0.0
 * @since 2022/9/3 - 15:26
 */
public class Sheep implements Serializable {

    private String name;

    private Integer age;

    private String color;

    /**
     * 羊的房子:引用类型
     */
    private House house;

    public House getHouse() {
        return house;
    }

    public void setHouse(House house) {
        this.house = house;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public String getColor() {
        return color;
    }

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

    public Sheep() {
    }

    public Sheep(String name, Integer age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    /**
     * 序列化的方式:进行深复制
     * 写着麻烦:用着简单。支持开闭原则
     * @return
     */
    public Object deepClone() {

        //创建流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;

        try {

            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this); //当前这个对象以对象流的方式输出

            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            Sheep copyObj = (Sheep) ois.readObject();

            return copyObj;

        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            return null;
        } finally {
            //关闭流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (Exception e2) {
                // TODO: handle exception
                System.out.println(e2.getMessage());
            }
        }

    }
}

Main

/**
 * 深复制
 *
 * @author Promsing(张有博)
 * @version 1.0.0
 * @since 2022/9/3 - 15:38
 */
public class DeepClient {

    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep sheep=new Sheep("黑",90,"heisee");
        sheep.setHouse(new House());
        Sheep clone = (Sheep)sheep.deepClone();
        System.out.println("原本的对象");
        System.out.println(sheep);
        System.out.println(sheep.getHouse());
        System.out.println("克隆的对象");
        System.out.println(clone);
        System.out.println(clone.getHouse());
    }

}

拓展

Spring使用原型模式:@scope(“prototype”)

public static void main(String[] args) throws IOException {
      //new一个容器
    AnnotationConfigWebApplicationContext context =
        new AnnotationConfigWebApplicationContext();
    System.out.println("run success");

    OrderService bean = context.getBean(OrderService.class);
}

//根据getBean点进去
public <T> T getBean(Class<T> requiredType) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(requiredType);
}

public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
}

后续走到了。AbstractBeanFactory类中的doGetBean方法中里边代码做判断mbd.isPrototype()

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			//代码省略~~~~
		}

		else {
			//代码省略~~~~

			try {
				//代码省略~~~~

				// Create bean instance.
                //判断是否是单例
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {

							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
                //判断是否是多例(原型)
                //这里会创建一个新的对象
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					//代码省略~~~~
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

		//代码省略~~~~
		}
		return (T) bean;
	}

ArrayList实现了Cloneable接口

public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

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

(0)

相关推荐

  • Java设计模式之原型模式(Prototype模式)介绍

    Prototype模式定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建. 如何使用原型模式 因为Java中的提供clone()方法来实现对象的克隆,所以Prototype模式实现一下子变得很简单.以勺子为例: 复制代码 代码如下: public abstract cl

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

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

  • 23种设计模式(3) java原型模式

    23种设计模式第三篇:java原型模式 定义: 通过复制现有的对象实例来创建新的对象实例. 实现: 实现Cloneable接口: Cloneable接口的作用是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法.在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常. 重写Object类中的clone方法: Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的

  • Java设计模式之Prototype原型模式

    一.场景描述 创建型模式中,从工厂方法模式,抽象工厂模式,到建造者模式,再到原型模式,我的理解是,创建对象的方式逐步从编码实现转向内存对象处理. 例如,在"仪器数据采集器"的子类/对象"PDF文件数据采集器"和"Excel文件数据采集器"的创建过程中, 工厂模式下定义各子类,并由(抽象)工厂类Factory创建,因此各子类可在类定义中定义各自的属性: 建造者模式下,通过不同的创建者类Builder创建不同的子对象,此时不再定义子类: 而原型模式下

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

    一.前言 原型模式是一种比较简单的模式,也非常容易理解,实现一个接口,重写一个方法即完成了原型模式.在实际应用中,原型模式很少单独出现.经常与其他模式混用,他的原型类Prototype也常用抽象类来替代. 该模式的思想就是将一个对象作为原型,对其进行复制.克隆,产生一个和原对象类似的新对象.在Java中,复制对象是通过clone()实现的,先创建一个原型类,通过实现Cloneable 接口 public class Prototype implements Cloneable { public

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

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

  • 浅谈Java设计模式之原型模式知识总结

    如何使用? 1.首先定义一个User类,它必须实现了Cloneable接口,重写了clone()方法. public class User implements Cloneable { private String name; private int age; private Brother brother; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }

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

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

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

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

  • 一文看懂JAVA设计模式之工厂模式

    工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式.该模式用于封装和管理对象的创建,是一种创建型模式.本文从一个具体的例子逐步深入分析,来体会三种工厂模式的应用场景和利弊. 1. 简单工厂模式 该模式对对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装.该模式通过向工厂传递类型来指定要创建的对象,其UML类图如下: 下面我们使用手机生产来讲解该模式: Phone类:手机标准规范

  • 一文带你了解Java万物之基之Object类

    目录 native方法 getClass方法 hashCode方法 equals方法 ==和equals的区别 clone方法 浅拷贝和深拷贝 toString方法 线程方法 finalize方法 Java是一门天然的面向对象的语言.而所有我们手动创造出来的类,都继承于同一个类,即Object类. 可以看一下Object类的结构 native方法 首先,超类拥有一个native方法 private static native void registerNatives(); static { re

  • 一文带你了解Java中的ForkJoin

    目录 什么是ForkJoin? ForkJoinTask 任务 ForkJoinPool 线程池 工作窃取算法 构造方法 提交方法 创建工人(线程) 例:ForkJoinTask实现归并排序 ForkJoin计算流程 前言: ForkJoin是在Java7中新加入的特性,大家可能对其比较陌生,但是Java8中Stream的并行流parallelStream就是依赖于ForkJoin.在ForkJoin体系中最为关键的就是ForkJoinTask和ForkJoinPool,ForkJoin就是利用

  • 一文带你了解Java中的Object类及类中方法

    目录 1. Object类介绍 2. 重写toString方法打印对象 3. 对象比较equals方法 4. hashCode方法 1. Object类介绍 Object是Java默认提供的一个类.Java里面除了Object类,所有的类都是存在继承关系的.默认会继承Object父 类.即所有类的对象都可以使用Object的引用进行接收. 范例:使用Object接收所有类的对象 class Person{} class Student{} public class Test { public s

随机推荐