Java GoF 23种设计模式-创建型模式-原型模式(Prototype Pattern)

文章目录

  • 一、模式定义
  • 二、模式动机
  • 三、模式结构
  • 四、代码实现
  • 五、优缺点
    • 5.1 原型模式优点
    • 5.2 原型模式缺点

一、模式定义

原型模式(Prototype Pattern)是一种创建型设计模式,使你能够复制已有对象, 而又无需使代码依赖它们所属的类。原型模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用原型模式。

二、模式动机

在我们应用程序可能有某些对象的结构比较复杂,但是我们又需要频繁的使用它们,如果这个时候我们来不断的新建这个对象势必会大大损耗系统内存的,这个时候我们需要使用原型模式来对这个结构复杂又要频繁使用的对象进行克隆。

从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。

原型模式大体上有三种适用场景:

  • 1、在需要一个类的大量对象的时候,使用原型模式是最佳选择,因为原型模式是在内存中对这个对象进行拷贝,要比直接new这个对象性能要好很多。

  • 2、如果一个对象的初始化需要很多其他对象的数据准备或其他资源的繁琐计算,那么可以使用原型模式,这样创建新的对象的时候,可以避免其他对象的数据准备和计算,直接得到当前对象的副本。

  • 3、当需要保留一个复杂对象的绝大部分信息,少量字段进行个性化设置的时候,也可以使用原型模式拷贝出现有对象的副本后再进行加工处理。

三、模式结构

Java GoF 23种设计模式-创建型模式-原型模式(Prototype Pattern)_第1张图片

原型模式包含如下角色:

  • 抽象原型角色[Abstract Prototype]:这是一个抽象角色,通常由一个java接口或java抽象类实现,此角色给出所有的具体原型类所需的接口。
  • 具体原型角色[Concrete Prototype]:被复制的对象,此角色需要实现抽象的原型角色所要求的接口。
  • 客户角色[Client]:客户类提出创建对象的请求。

四、代码实现

角色
抽象原型角色 java.lang.Cloneable.java
具体原型角色 Student.java、School.java
客户角色 ClientTest.java

School.java

package com.design.demo.prototype;


import java.util.Date;

/**
 * 学校信息
 * @author administrator
 * @date 2020-05-16 22:40
 */
public class School implements Cloneable {
     

    /**
     * 学校名称
     **/
    private String name;

    /**
     * 学校地址
     **/
    private String adress;

    /**
     * 学校联系电话
     **/
    private String telNo;

    /**
     * 学校注册登记日期
     **/
    private Date regeditDate;


    public String getName() {
     
        return name;
    }

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

    public String getAdress() {
     
        return adress;
    }

    public void setAdress(String adress) {
     
        this.adress = adress;
    }

    public String getTelNo() {
     
        return telNo;
    }

    public void setTelNo(String telNo) {
     
        this.telNo = telNo;
    }

    public Date getRegeditDate() {
     
        return regeditDate;
    }

    public void setRegeditDate(Date regeditDate) {
     
        this.regeditDate = regeditDate;
    }
    
    @Override
    protected School clone() throws CloneNotSupportedException {
     
        return (School) super.clone();
    }
}

Student.java

package com.design.demo.prototype;

/**
 * 学生信息
 * @author administrator
 * @date 2020-05-16 22:40
 */
public class Student implements Cloneable {
     

    /**
     * 学生姓名
     **/
    private String name;

    /**
     * 学生年龄
     **/
    private int age;

    /**
     * 学生所属学校
     **/
    private School school;

    public String getName() {
     
        return name;
    }

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

    public int getAge() {
     
        return age;
    }

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

    public School getSchool() {
     
        return school;
    }

    public void setSchool(School school) {
     
        this.school = school;
    }

    @Override
    protected Student clone() throws CloneNotSupportedException {
     
        Student clone = (Student) super.clone();
        clone.setSchool(school.clone());
        return clone;
    }
}
package com.design.demo.prototype;

import java.util.Date;

/**
 * @author administrator
 * @date 2020-05-16 22:45
 */
public class ClientTest {
     

    public static void main(String[] args) throws CloneNotSupportedException {
     

        School school = new School();
        school.setName("五道口职业技术学院");
        school.setAdress("中国.北京");
        school.setTelNo("18888888888");
        school.setRegeditDate(new Date());

        Student std = new Student();
        std.setName("张三");
        std.setAge(20);
        std.setSchool(school);

        Student stdClone = std.clone();
        stdClone.setName("李四");
        stdClone.getSchool().setName("家里蹲大学");

        System.out.println("学生姓名:" + std.getName() + " 学校名称:" + std.getSchool().getName() + " 学校注册日期:" + std.getSchool().getRegeditDate());
        System.out.println("学生姓名:" + stdClone.getName() + " 学校名称:" + stdClone.getSchool().getName() + " 学校注册日期:" + std.getSchool().getRegeditDate());
    }

}

使用clone方法创建的新对象的构造函数是不会被执行的,也就是说会绕过任何构造函数(有参和无参),因为clone方法的原理是从堆内存中以二进制流的方式进行拷贝,直接分配一块新内存。

浅复制和深复制的概念:

  • 浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。
  • 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。

五、优缺点

5.1 原型模式优点

  • 你可以克隆对象, 而无需与它们所属的具体类相耦合。
  • 你可以克隆预生成原型, 避免反复运行初始化代码。
  • 你可以更方便地生成复杂对象。
  • 你可以用继承以外的方式来处理复杂对象的不同配置。

5.2 原型模式缺点

  • 克隆包含循环引用的复杂对象会非常麻烦,需要编写较为复杂的代码

你可能感兴趣的:(设计模式,设计模式,java)