设计模式五: 原型模式(Prototype)

简介: 简介原型模式是属于创建型模式的一种,是通过拷贝原型对象来创建新的对象.万能的Java超类Object提供了clone()方法来实现对象的拷贝.可以在以下场景中使用原型模式:构造函数创建对象成本太大(性能或安全成本)要保存对象的状态, 且状态变化较小, 不会过多占用内存时(状态变化较大的使用状态模式会更合适)意图使用原型实例指定要创建的对象类型,并通过拷贝这个原型来创建新对象。

简介

原型模式是属于创建型模式的一种,是通过拷贝原型对象来创建新的对象.

万能的Java超类Object提供了clone()方法来实现对象的拷贝.

可以在以下场景中使用原型模式:

  1. 构造函数创建对象成本太大(性能或安全成本)
  2. 要保存对象的状态, 且状态变化较小, 不会过多占用内存时(状态变化较大的使用状态模式会更合适)

意图

使用原型实例指定要创建的对象类型,并通过拷贝这个原型来创建新对象。

类图

原型模式

实现

一. 浅拷贝和深拷贝的概念

Object.clone()方法实现的是对象的浅拷贝, 所谓浅拷贝就是当对象中有复杂引用类型的域变量时, 只拷贝该域变量的引用而不是内容, 当有任一方法修改域变量的状态时会同时影响原型对象及拷贝对象, 实际上他们共用了同一个堆内存. 深拷贝创建的对象即是对原对象的完全拷贝,对任一对象的操作不会影响其他对象的状态.

java中提供了Cloneable接口, 约定实现接口Cloneable且重写Object.clone()方法的类可以用来拷贝自身. Cloneable是一个标记接口, 其中没有定义任何方法.

二. 下面的代码演示了使用clone()方法实现的深拷贝,这种方式更适合用于比较简单的对象,否则clone()方法的实现可能会变得异常复杂.

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class CarProperty implements Cloneable {

    private String power;
    private double maxSpeed;
    private double oilPerKm;

    public Object clone(){
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return obj;
    }
}

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Car implements Cloneable {

    private String brand;
    private double price;
    private CarProperty carProperty;

    /**
     * 深拷贝在此实现,对于复杂的应用类型, 这里的代码可能会相当复杂,如果类有修改(新增成员变量等),这里也需要相应修改
     * @return
     */
    public Object clone(){
        Object car = null;
        try {
            car = super.clone();
            CarProperty carPropertyClone = (CarProperty)this.getCarProperty().clone();
            ((Car)car).setCarProperty(carPropertyClone);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return car;
    }

    public static void main(String[] args) {

        CarProperty carProperty = new CarProperty("8匹",250,30);
        Car car= new Car("BMW",200,carProperty);

        Car copy = (Car) car.clone();
        System.out.println("copy最大速度为: "+copy.getCarProperty().getMaxSpeed());
        System.out.println("原型最大速度为: "+car.getCarProperty().getMaxSpeed());
        car.getCarProperty().setMaxSpeed(360);
        System.out.println("copy最大速度为: "+copy.getCarProperty().getMaxSpeed());
        System.out.println("原型最大速度为: "+car.getCarProperty().getMaxSpeed());
    }

}

三. 深拷贝的其他实现方式: 除了上面的方法,还可以使用反射机制创建对象的深拷贝, 另外一种更简单的方式是使用序列化;
下面的代码使用序列化方式实现对象的深拷贝,需实现Serializable接口.

import java.io.*;

public class DeepCloneBase implements Serializable {
    public Object deepClone() {
        ByteArrayOutputStream byteArrayOutputStream = null;
        ObjectOutputStream objectOutputStream = null;
        ByteArrayInputStream byteArrayInputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);
            byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            return objectInputStream.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                byteArrayOutputStream.close();
                objectOutputStream.close();
                byteArrayInputStream.close();
                objectInputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serializable;

@Data
@AllArgsConstructor
public class MyCar extends DeepCloneBase {

    private String brand;
    private double price;
    private CarProperty carProperty;

    public static void main(String[] args) throws  Exception{
        // 注意CarProperty也需要实现Serializable接口,代码不再单独列出
        CarProperty carProperty = new CarProperty("8匹",250,30);
        MyCar car= new MyCar("BMW",200,carProperty);

        MyCar copy = (MyCar)car.deepClone();

        if (copy!=null){
            System.out.println("copy最大速度为: "+copy.getCarProperty().getMaxSpeed());
            System.out.println("原型最大速度为: "+car.getCarProperty().getMaxSpeed());
            car.getCarProperty().setMaxSpeed(360);
            System.out.println("copy最大速度为: "+copy.getCarProperty().getMaxSpeed());
            System.out.println("原型最大速度为: "+car.getCarProperty().getMaxSpeed());
        }else{
            System.out.println("对象没拷贝成功....");
        }
    }
}

总结

优点: 1. 如果对象创建比较复杂, 可以简化创建过程, 提高效率;2. 可以保留对象状态;
缺点: 对于clone()方式,如果类有修改则需要修改clone()的实现,不符合开闭原则; 复杂对象的clone逻辑可能较复杂;

JDK

java.lang.Object#clone()

相关文章
|
1月前
|
设计模式 安全 Java
【设计模式】原型模式
【设计模式】原型模式
|
2月前
|
设计模式 Java 关系型数据库
23种设计模式 —— 原型模式【克隆羊、浅拷贝、深拷贝】
23种设计模式 —— 原型模式【克隆羊、浅拷贝、深拷贝】
38 1
|
4月前
|
设计模式 存储
二十三种设计模式全面解析-原型模式进阶之原型管理器:集中管理对象原型的设计模式之道
二十三种设计模式全面解析-原型模式进阶之原型管理器:集中管理对象原型的设计模式之道
|
7天前
|
设计模式 Java
小谈设计模式(10)—原型模式
小谈设计模式(10)—原型模式
|
1月前
|
设计模式 Java
设计模式之原型模式
设计模式之原型模式
|
3月前
|
设计模式 存储 JSON
Java设计模式-原型模式
原型模式也是创建对象的一种方式,它一般用在这样的场景:系统中存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂而且耗费资源。这个时候使用原型模式的克隆方式,能够节省不少时间。比如Java 类中提供的`Object clone()`就是原型模式的应用。
30 1
Java设计模式-原型模式
|
3月前
|
设计模式
设计模式 | 原型模式
设计模式 | 原型模式
21 0
|
3月前
|
设计模式 Go 开发工具
Golang设计模式——13原型模式
Golang设计模式——13原型模式
23 0
|
3月前
|
设计模式 缓存 前端开发
【设计模式】之原型模式
原型模式是一种常用的设计模式,它通过克隆现有对象来创建新对象,减少了重复代码并提高了性能。在前端开发中,原型模式常用于对象创建、数据共享和缓存管理等场景。然而,需要注意对共享状态的管理和克隆操作的复杂性。
36 0
|
4月前
|
设计模式
设计模式之原型模式
先来说一下原型模式的应用场景 * 创建新对象成本较大,如初始化需要占用较长的时间,占用太多的CPU资源或网络资源。在这种情况下,可以通过原型模式对已有对象进行复制来获得新对象,如果是相似对象,可以对其成员变量稍作修改。 * 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。