建立型设计模式之原型模式

模式介绍

原型模式(Prototype Pattern)简单来讲就是程序界的复制粘贴,它能够实现对象的深拷贝。html

咱们建立一个对象,一般有3种方式:java

  • new 关键字
  • 反射
  • 实现Cloneable接口的clone()方法

若是须要对已有的对象进行复制,且建立对象成本较高(例如须要较多的I/O),能够考虑使用原型模式。spring

在原型模式中,所发动建立的对象经过请求原型对象来拷贝原型对象本身来实现建立过程,固然所发动建立的对象须要知道原型对象的类型。这里也就是说所发动建立的对象只须要知道原型对象的类型就能够得到更多的原型实例对象,至于这些原型对象时如何建立的根本不须要关心。设计模式

模式优缺点

优势

一、若是建立新的对象比较复杂时,能够利用原型模式简化对象的建立过程,同时也可以提升效率。数组

二、可使用深克隆保持对象的状态。bash

三、原型模式提供了简化的建立结构。ide

四、原型模式向客户隐藏了建立对象的复杂性。客户只须要知道要建立对象的类型,而后经过请求就能够得到和该对象如出一辙的新对象,无须知道具体的建立过程。性能

缺点

一、在实现深克隆的时候可能须要比较复杂的代码。 咱们虽然能够利用原型模式来得到一个新对象,但有时对象的复制可能会至关的复杂,好比深克隆。this

二、须要为每个类配备一个克隆方法,并且这个克隆方法须要对类的功能进行通盘考虑,这对全新的类来讲不是很难,但对已有的类进行改造时,不必定是件容易的事,必须修改其源代码,违背了“开闭原则”。spa

实现

角色

Prototype:抽象原型类。声明克隆自身的接口。 ConcretePrototype:具体原型类。实现克隆的具体操做。 Client:客户类。让一个原型克隆自身,从而得到一个新的对象。

接口

咱们都知道Object是祖宗,全部的Java类都继承至Object,而Object类提供了一个clone()方法,该方法能够将一个java对象复制一份,所以在java中能够直接使用clone()方法来复制一个对象。可是须要实现clone的Java类必需要实现一个接口:Cloneable.该接口表示该类可以复制且具体复制的能力,若是不实现该接口而直接调用clone()方法会抛出CloneNotSupportedException异常。
复制代码

步骤

第一步:定义抽象原型。

package net.ijiangtao.tech.designpattern.prototype;

import lombok.*;

import java.util.HashMap;
import java.util.Map;

/** * 定义一个抽象原型 * * @author ijiangtao * @create 2019-07-17 21:20 **/
@Getter
@Setter
@NoArgsConstructor  //lombok : 无参构造
@AllArgsConstructor //lombok : 全参构造
@ToString
public class Prototype implements Cloneable{

    private Integer id;

    private String name;

    private Map<String, Double> scores;

    @Override
    protected Prototype clone() {
        Prototype filePrototype = null;
        try {
            //有了下面这句话,基本类型就能克隆了
            filePrototype = (FileConcretePrototype) super.clone();
            
            //下面要对每个复杂对象进行分别克隆
            filePrototype.scores = (Map<String, Double>) ((HashMap)this.scores).clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return filePrototype;
    }

}
复制代码

第二步:定义具体原型。

package net.ijiangtao.tech.designpattern.prototype;

import java.util.Map;

/** * 定义具体原型 * * @author ijiangtao * @create 2019-07-17 21:21 **/
public class FileConcretePrototype extends Prototype {

    public FileConcretePrototype(Integer id, String name, Map<String, Double> scores) {
        super(id, name, scores);
    }

    public void show() {
        System.out.println(" File Data : ");
        System.out.println("file name : " + this.getName());
        System.out.println("file id : " + this.getId());
        System.out.println("file scores : " + this.getScores());
    }

}
复制代码

第三步:定义用户去模拟对象克隆。

package net.ijiangtao.tech.designpattern.prototype;

import java.util.HashMap;
import java.util.Map;

/**
 * client
 *
 * @author ijiangtao
 * @create 2019-07-17 21:27
 **/
public class Client {


    public static void main(String[] args) {

        String fileName = "scores文件";
        int fileId = 1;
        Map<String, Double> fileScores = new HashMap<>();
        fileScores.put("张三", 99.99);
        fileScores.put("李斯", 79.99);

        //第一步建立出一个实例对象
        FileConcretePrototype fileA = new FileConcretePrototype(fileId, fileName, fileScores);

        //第二步克隆出来几个
        FileConcretePrototype fileB = (FileConcretePrototype) fileA.clone();
        FileConcretePrototype fileC = (FileConcretePrototype) fileA.clone();

        //第三步:输出一下克隆出来的对象是否有变化
        fileB.show();
        fileC.show();

    }
}

复制代码

最后输出是:

File Data : 
file name : scores文件
file id : 1
file scores : {李斯=79.99, 张三=99.99}
 File Data : 
file name : scores文件
file id : 1
file scores : {李斯=79.99, 张三=99.99}
复制代码

咱们能够看到,克隆出来的两个文件和以前的文件是同样的,并且咱们实现了深拷贝,对于数组、引用等对象一样的适用。

特色

Java中任何实现了Cloneable接口的类均可以经过调用clone()方法来复制一份自身而后传给调用者。通常而言,clone()方法知足:

(1) 对任何的对象x,都有x.clone() !=x,即克隆对象与原对象不是同一个对象。

//第一步建立出一个实例对象
FileConcretePrototype fileA = new FileConcretePrototype(fileId, fileName, fileScores);

//第二步克隆出来几个
FileConcretePrototype fileB = (FileConcretePrototype) fileA.clone();
FileConcretePrototype fileC = (FileConcretePrototype) fileA.clone();

//第三步:引用赋值
FileConcretePrototype fileA2 =fileA;

System.out.println(fileA==fileB);//输出false
System.out.println(fileA==fileA2);//输出true
复制代码

(2) 对任何的对象x,都有x.clone().getClass()==x.getClass(),即克隆对象与原对象的类型同样。

//第一步建立出一个实例对象
FileConcretePrototype fileA = new FileConcretePrototype(fileId, fileName, fileScores);

//第二步克隆出来几个
FileConcretePrototype fileB = (FileConcretePrototype) fileA.clone();
FileConcretePrototype fileC = (FileConcretePrototype) fileA.clone();

//第三步:引用赋值
FileConcretePrototype fileA2 =fileA;

System.out.println(fileA.getClass()==fileC.getClass()); //输出true
复制代码

(3) 若是对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。

首先重写 equals 和 hashCode 方法:

@EqualsAndHashCode // lombok : over write equals and hashCode methods based on relevant fields.
public class FileConcretePrototype extends Prototype 复制代码

而后与克隆之后的对象比较:

//第一步建立出一个实例对象
FileConcretePrototype fileA = new FileConcretePrototype(fileId, fileName, fileScores);

//第二步克隆出来几个
FileConcretePrototype fileB = (FileConcretePrototype) fileA.clone();
FileConcretePrototype fileC = (FileConcretePrototype) fileA.clone();

//第三步:引用赋值
FileConcretePrototype fileA2 =fileA;

System.out.println(fileA.equals(fileB));//输出true
System.out.println(fileC.equals(fileB));//输出true
复制代码

相关连接

深刻理解原型模式 ——经过复制生成实例

设计模式之原型模式

设计模式读书笔记-原型模式

java的浅拷贝和深拷贝

spring中的scope详解

spring的scope为prototype的bean的正确使用方法

BeanUtils.copyProperties()方法 && 关于BeanUtil.copyProperties性能


Wechat-westcall
相关文章
相关标签/搜索