设计模式之“原型模式(ProtoType)”

一、原型模式(ProtoType)

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

白话解释:用于创建重复的对象,同时有能保证性能(这种类型的设计模式属于创建型设计模式,他提供了一种创建对象的最佳方式)

主要解决:在运行期间建立和删除原型

使用场景:

  1. 当一个系统应该独立于他的产品创建,构成和表达时
  2. 当要实例化的类是在运行时时刻指定时,例如,通过动态装载
  3. 为了避免创建一个与产品类层次平行的工厂类层次时
  4. 当一个类的实例只能有几个不同状态组合中的一种时
  5. 建立相对应数目的原型并克隆他们可能比每次合适的状态手工实例化该类更方便一些
  6. 资源优化场景
  7. 类初始化需要消耗非常多的资源,这个资源包括数据、硬件资源等
  8. 性能和安全要求的场景
  9. 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
  10. 一个对象多个修改者的场景
  11. 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式已经与Java融为浑然一体,大家可以随手拿来使用

如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例

关键代码:

  1. 实现克隆操作,在Java中继承Cloneable,重写clone,在C语言中可以使用Object类的MemberWiseClone()方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝
  2. 原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,他同样要求这些“易变类”拥有稳定的接口

应用实例:

  1. 细胞分裂
  2. Java中的Object clone();方法

优点

  1. 性能提高
  2. 逃避构造函数的约束

缺点:

  1. 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定是容易的,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候
  2. 必须实现Cloneable接口

注意事项

  1. 与通过对一个类进行实例化来构造新对象不同的是原型模式是通过拷贝一个现有对象生成新对象的
  2. 浅拷贝实现Cloneable,重写
  3. 深拷贝是通过实现Serializable读取二进制流
  4. 有点赋值的意思

 

二、原型模式结构图

 

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

 三、浅拷贝代码

逻辑代码

package com.proto;

/**
 * 原型模式
 *      1.Cloneable 替代了 MemberwiseClone()
 *      2.就是浅拷贝了下,修改还是靠set
 *
 * @author 王子威
 * @date 2022/7/28
 */
public class ConcretePrototypeOne implements Cloneable
{

    private String name;
    private String sex;
    private String age;
    private String timeArea;
    private String company;

    /**
     * 构造函数
     *      初始化
     *      加载简历人员
     * @param name 名字
     */
    public ConcretePrototypeOne(String name)
    {
        this.name = name;
    }

    /**
     * 个人信息
     *
     * @param sex 性别
     * @param age 年龄
     */
    public void setPersonalInfo(String sex, String age)
    {
        this.sex = sex;
        this.age = age;
    }

    /**
     * 工作经历
     *
     * @param timeArea 时间
     * @param company 公司
     */
    public void setWorkExperience(String timeArea, String company)
    {
        this.timeArea = timeArea;
        this.company = company;
    }

    /**
     * 显示内容
     */
    public void Display()
    {
        System.out.println("name = " + name);
        System.out.println("sex = " + sex);
        System.out.println("age = " + age);
        System.out.println("timeArea = " + timeArea);
        System.out.println("company = " + company);
    }

    /**
     * 拷贝(原型模式关键点)
     * 
     * @return 需要强转为自己需要的对象
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException
    {
        return super.clone();
    }
}

 

测试代码

package com.proto;

/**
 * 原型模型测试方法
 *
 * @author 王子威
 * @date 2022/7/28
 */
public class MainTest
{
    public static void main(String[] args) throws CloneNotSupportedException
    {
        // 对象1
        ConcretePrototypeOne a = new ConcretePrototypeOne("wzw");
        a.setPersonalInfo("男","18");
        a.setWorkExperience("1999-2000","xxx公司");
        System.out.println("a = " + a);

        // 对象2
        ConcretePrototypeOne b = (ConcretePrototypeOne) a.clone();
        b.setWorkExperience("1999-2001","ooo公司");
        System.out.println("b = " + b);

        // 对象3
        ConcretePrototypeOne c = (ConcretePrototypeOne) a.clone();
        c.setPersonalInfo("男","18");
        System.out.println("c = " + c);

     // 显示
        a.Display();
        b.Display();
        c.Display();
    }
}

 结果图

 

四、深拷贝代码

逻辑代码

package com.proto;

/**
 * 原型模式
 * 1.Cloneable 替代了 MemberwiseClone()
 * 2.这里采用的是深复制的方案进行处理过
 * 3.将工作经历提取出来成为对象类
 *
 * @author 王子威
 * @date 2022/7/28
 */
public class ConcretePrototypeTwo implements Cloneable
{

    private String name;
    private String sex;
    private String age;
    /**
     * 引用工作经历对象
     */
    private WorkExperience work;

    /**
     * 构造函数
     * 初始化
     * 加载简历人员
     *
     * @param name 名字
     */
    public ConcretePrototypeTwo(String name)
    {
        this.name = name;
        // 在实体化简历时一起实体化“工作经历”对象
        work = new WorkExperience();
    }

    /**
     * 拷贝工作经历对象
     *
     * @param work
     * @throws CloneNotSupportedException
     */
    private ConcretePrototypeTwo(WorkExperience work) throws CloneNotSupportedException
    {
        this.work = (WorkExperience) work.clone();
    }

    /**
     * 个人信息
     *
     * @param sex 性别
     * @param age 年龄
     */
    public void setPersonalInfo(String sex, String age)
    {
        this.sex = sex;
        this.age = age;
    }

    /**
     * 工作经历
     *
     * @param timeArea 时间
     * @param company  公司
     */
    public void setWorkExperience(String timeArea, String company)
    {
        work.setTimeArea(timeArea);
        work.setCompany(company);
    }

    /**
     * 显示内容
     */
    public void Display()
    {
        System.out.println("name = " + name);
        System.out.println("sex = " + sex);
        System.out.println("age = " + age);
        System.out.println("timeArea = " + work.getTimeArea());
        System.out.println("company = " + work.getCompany());
    }

    /**
     * 深拷贝(原型模式关键点)
     *
     * @return 需要强转为自己需要的对象
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException
    {
        ConcretePrototypeTwo deepClone = new ConcretePrototypeTwo(this.work);
        deepClone.name = this.name;
        deepClone.sex = this.sex;
        deepClone.age = this.age;
        return deepClone;
    }
}

 

测试代码

package com.proto;

import org.junit.Test;

/**
 * 原型模型测试方法
 *
 * @author 王子威
 * @date 2022/7/28
 */
public class MainTest
{
    @Test
    public void protoDeepClone() throws CloneNotSupportedException
    {
        // 对象1
        ConcretePrototypeTwo a = new ConcretePrototypeTwo("wzw");
        a.setPersonalInfo("男","18");
        a.setWorkExperience("1999-2000","xxx公司");
        System.out.println("a = " + a);

        // 对象2
        ConcretePrototypeTwo b = (ConcretePrototypeTwo) a.clone();
        b.setWorkExperience("1999-2001","ooo公司");
        System.out.println("b = " + b);

        // 对象3
        ConcretePrototypeTwo c = (ConcretePrototypeTwo) a.clone();
        c.setWorkExperience("1999-2002","yyy公司");
        System.out.println("c = " + c);

        // 显示
        a.Display();
        b.Display();
        c.Display();
    }

}

 

结果图

 

 

五、总结

  1. 在Cloneable中有方法Clone(),这样你就只需要实现这个接口就可以完成原型模式了
  2. 实现了解耦,当只想改某一个对象内容时就直接修改,而且不会影响到其他的了
  3. 减少了构造函数执行的时间
  4. 一般在初始化的信息不发生改变的情况下,克隆是最好的方法,既隐藏了对象创建的细节,有对性能是大大的提高
  5. 不用重新初始化对象,而是动态的获取对象运行时的状态
  6. 深拷贝时需要注意再赋值和子对象的处理
  7. java基础之“深复制和浅复制的区别”
posted @ 2022-07-28 11:46  骚哥  阅读(297)  评论(0编辑  收藏  举报