详解java设计模式之原型模式(prototypepattern)(代码片段)

虫链JavaLibrary 虫链JavaLibrary     2023-02-17     441

关键词:

模式简介

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在软件系统中,有时候需要多次创建某一类型的对象,为了简化创建过程,可以只创建一个对象,然后再通过克隆的方式复制出多个相同的对象,这就是原型模式的设计思想。

原型模式的基本工作原理是通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象复制原型自己来实现创建过程。

举例说明 👇

《西游记》中孙悟空拔毛变小猴的故事几乎人人皆知,孙悟空可以用猴毛根据自己的形象,复制出很多跟自己长得一模一样的身外身来。

孙悟空这种复制出多个身外身的方式在面向对象设计领域里称为原型(Prototype)模式。在面向对象系统中,使用原型模式来复制一个对象自身,从而克隆出多个与原型对象一模一样的对象

在软件系统中,有些对象的创建过程较为复杂,而且有时候需要频繁创建。原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的意图所在。



模式结构

原型模式包含如下角色 👇

  1. Prototype(抽象原型类)

抽象原型类是定义具有克隆自己的方法的接口,是所有具体原型类的公共父类,可以是抽象类,也可以是接口。

  1. ConcretePrototype(具体原型类)

具体原型类实现具体的克隆方法,在克隆方法中返回自己的一个克隆对象。

  1. Client(客户类)

客户类让一个原型克隆自身,从而创建一个新的对象。在客户类中只需要直接实例化或通过工厂方法等方式创建一个对象,再通过调用该对象的克隆方法复制得到多个相同的对象。


模式案例

原型模式的克隆分为浅克隆和深克隆。

  • 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

  • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

下面通过两个分别实现浅克隆和深克隆的实例来进一步学习并理解原型模式。

案例1:原型模式实例之邮件复制(浅克隆)


  1. 抽象原型类Object(无需创建)

Object作为抽象原型类,在Java语言中,所有的类都是Object的子类,在Object 中提供了克隆方法clone(),用于创建一个原型对象,其 clone()方法具体实现由JVM完成,用户在使用时无须关心。

  1. 附件类 Attachment

为了更好地说明浅克隆和深克隆的区别,在本实例中引入了附件类Attachment,邮件类Email与附件类是组合关联关系,在邮件类中定义一个附件类对象,作为其成员对象。

package prototype;

/**
 * @author mengzhichao
 * @create 2021-11-10-22:20
 */
public class Attachment 

    public void download()
        System.out.println("下载附件");
    

  1. 具体原型类Email(邮件类)

Email类是具体原型类,也是Object类的子类。在Java语言中,只有实现了Cloneable接口的类才能够使用clone()方法来进行复制,因此Email类实现了Cloneable接口。在Email类中覆盖了Object的clone()方法,通过直接或者间接调用Object的clone()方法返回一个克隆的原型对象。在Email类中定义了一个成员对象attachment,其类型为Attachment。

package prototype;



/**
 * @author mengzhichao
 * @create 2021-11-10-22:18
 */
public class Email implements Cloneable 

    private Attachment attachment=null;

    public Email()
        this.attachment=new Attachment();
    

    @Override
    public Object clone()
        Email clone =null;

        try 
            clone=(Email) super.clone();
        catch (CloneNotSupportedException e)
            System.out.println("Clone failure!");
        

        return clone;
    

    public Attachment getAttachment()
        return this.attachment;
    

    public void display()
        System.out.println("查看邮件");
    


  1. 客户端测试类Client

在Client 客户端测试类中,比较原型对象和复制对象是否一致﹐并比较其成员对象attachment的引用是否一致。

package prototype;

/**
 * @author mengzhichao
 * @create 2021-11-10-22:29
 */
public class Client 
    public static void main(String[] args) 
        Email email,copyEmail;

        email=new Email();

        copyEmail= (Email) email.clone();

        System.out.println("email == copyEmail?");
        System.out.println(email == copyEmail);

        System.out.println("email.getAttachment() == copyEmail.getAttachment()?");
        System.out.println(email.getAttachment() == copyEmail.getAttachment());
    

结果如下

  • 通过结果可以看出,表达式(email==copyEmail)结果为false,即通过复制得到的对象与原型对象的引用不一致,也就是说明在内存中存在两个完全不同的对象,一个是原型对象,一个是克隆生成的对象。
  • 但是表达式(email.getAttachment( ) == copyEmail.getAttachment())结果为true,两个对象的成员对象是同一个,说明虽然对象本身复制了一份,但其成员对象在内存中没有复制,原型对象和克隆对象维持了对相同的成员对象的引用。

案例2:原型模式实例之邮件复制(深克隆)

使用深克隆实现邮件复制,即复制邮件的同时复制附件。

  1. 附件类 Attachment

作为Email类的成员对象,在深克隆中,Attachment类型的对象也将被写入流中,因此Attachment类也需要实现Serializable接口。

package prototype2;

import java.io.Serializable;

/**
 * @author mengzhichao
 * @create 2021-11-10-22:20
 */
public class Attachment implements Serializable 

    public void download()
        System.out.println("下载附件");
    

  1. 具体原型类Email(邮件类)

Email作为具体原型类,由于实现的是深克隆,无须使用Object的 clone()方法,因此无须实现Cloneable接口;可以通过序列化的方式实现深克隆(代码中粗体部分),由于要将Email类型的对象写入流中,因此Email类需要实现Serializable接口。

package prototype2;



import java.io.*;

/**
 * @author mengzhichao
 * @create 2021-11-10-22:18
 */
public class Email implements Serializable 

    private Attachment attachment=null;

    public Email()
        this.attachment=new Attachment();
    


    public Object deepClone() throws IOException,ClassNotFoundException, OptionalDataException
        //将对象写入流中
        ByteArrayOutputStream bao=new ByteArrayOutputStream();
        ObjectOutputStream oos =new ObjectOutputStream(bao);
        oos.writeObject(this);

        //将对象从流中取出
        ByteArrayInputStream bis =new ByteArrayInputStream(bao.toByteArray());
        ObjectInputStream ois =new ObjectInputStream(bis);
        return (ois.readObject());
    


    public Attachment getAttachment()
        return this.attachment;
    

    public void display()
        System.out.println("查看邮件");
    

  1. 客户端测试类Client

在Client客户端测试类中,我们仍然比较深克隆后原型对象和拷贝对象是否一致,并比较其成员对象attachment的引用是否一致。

package prototype2;

/**
 * @author mengzhichao
 * @create 2021-11-11-22:28
 */
public class Client 

    public static void main(String[] args) 
        Email email,copyEmail = null;
        email=new Email();

        try 
            copyEmail = (Email) email.deepClone();
        catch (Exception e)
            e.printStackTrace();
        

        System.out.println("email==copyEmail?");
        System.out.println(email==copyEmail);

        System.out.println("email.getAttachment()==copyEmail.getAttachment()?");
        System.out.println(email.getAttachment()==copyEmail.getAttachment());
    

通过结果可以看出,表达式( email==copyEmail)结果为false,即通过复制得到的对象与原型对象的引用不一致,表达式( email.getAttachment()==copyEmail.getAttachment())结果也为false,原型对象与克隆对象对成员对象的引用不相同,说明其成员对象也复制了一份。


模式总结

  • 优缺点:原型模式最大的优点在于可以快速创建很多相同或相似的对象,简化对象的创建过程,还可以保存对象的一些中间状态。
    其缺点在于需要为每一个类配备一个克隆方法,因此对已有类进行改造比较麻烦﹐需要修改其源代码,并且在实现深克隆时需要编写较为复杂的代码。

  • 适用于:创建新对象成本较大,新的对象可以通过原型模式对已有对象进行复制来获得。系统要保存对象的状态,而对象的状态变化很小,需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。


拓展内容

带原型管理器的原型模式

  • 原型模式的一种改进形式是带原型管理器的原型模式。

原型管理器(Prototype Manager)角色创建具体原型类的对象,并记录每一个被创建的对象。原型管理器的作用与工厂相似,其中定义了一个集合用于存储原型对象,如果需要某个对象的一个克隆,可以通过复制集合中对应的原型对象来获得。在原型管理器中针对抽象原型类进行编程,以便扩展。

下面使用代码模拟演示一个颜色原型管理器的实现过程。

  1. 抽象原型类 MyColor
package prototypemanager;

/**
 * @author mengzhichao
 * @create 2021-11-14-10:30
 */
public interface MyColor extends Cloneable 

    public Object clone();

    public void display();

  1. 具体原型类 Red
package prototypemanager;

/**
 * @author mengzhichao
 * @create 2021-11-14-10:32
 */
public class Red implements MyColor 
    @Override
    public Object clone() 
        Red r=null;
        try 
            r = (Red) super.clone();
        catch (Exception e)

        
        return r;
    

    @Override
    public void display() 
        System.out.println("This is Red");
    

  1. 具体原型类 Blue
package prototypemanager;

/**
 * @author mengzhichao
 * @create 2021-11-14-10:36
 */
public class Blue implements MyColor 
    @Override
    public Object clone() 
        Blue b=null;
        try 
            b = (Blue) super.clone();
        catch (Exception e)

        
        return b;
    
    @Override
    public void display() 
        System.out.println("This is Blue");
    

  1. 原型管理器类 PrototypeManager
package prototypemanager;

import java.util.Hashtable;

/**
 * @author mengzhichao
 * @create 2021-11-14-10:37
 */
public class PrototypeManager 

    private Hashtable ht =new Hashtable();

    public PrototypeManager() 
        ht.put("red",new Red());
        ht.put("blue",new Blue());
    

    public void addColor(String key,MyColor obj)
        ht.put(key,obj);
    

    public MyColor getColor(String key)
        return (MyColor) ((MyColor)ht.get(key)).clone();
    


  1. 客户端测试类 Client
package prototypemanager;

/**
 * @author mengzhichao
 * @create 2021-11-14-10:47
 */
public class Client 

    public static void main(String[] args) 
        PrototypeManager pm =new PrototypeManager();

        MyColor obj1=pm.getColor("red");
        obj1.display();

        MyColor obj2=pm.getColor("red");
        obj2.display();

        System.out.println(obj1==obj2);

    

运行结果如下

  • 在PrototypeManager中定义了一个 Hashtable类型的集合,使用“键值对”来存储原型对象,客户端可以通过Key来获取对应原型对象的克隆对象。PrototypeManager类提供了工厂方法,用于返回一个克隆对象。

更多精彩文章访问:https://blog.csdn.net/weixin_45692705?spm=1011.2124.3001.5343

关注一下下方公众号,谢谢了! 👇

创建者模式之原型模式

原型模式:Prototype原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对... 查看详情

headfirst设计模式之原型模式

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种比较简单的模式,也非常容易理解,实现一个接口,重写一个方法即完成了原型模式。在实际应用中,原型模式很少单独出现。经常与其他... 查看详情

设计模式之原型模式

...进行复制、克隆,产生一个和原对象类似的新对象。这种设计模式涉及到三个角色:1.客户(Client)角色:客户类提出创建对象的请求。2.抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给... 查看详情

设计模式之原型模式

设计模式之原型模式Nov23,2015原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象。正文对于原型模式,我们可以利用JavaScript特有的原型继承特性去创建对象的方式,也就是创建的一个... 查看详情

设计模式之原型设计模式(代码片段)

原型设计模式原型设计模式的定义是原型实例指定对象的类型,通过拷贝这些原型来创建新的对象原型设计的例子以<>例子为例子:我们求职投简历,经历这一栏在投不同的公司需要修改,我们不要再去创建个人信息、工作经... 查看详情

尚硅谷设计模式学习---[原型模式(prototype模式),深拷贝与浅拷贝](代码片段)

...#x1f680;🚀🚀尚硅谷传送门==>B站尚硅谷Java设计模式❤❤❤感谢尚硅谷❤❤❤🛴🛴🛴最近开始计划学习一下设计模式了,加油!!!目录原型模式原型模式引入浅拷贝深拷贝实现深拷贝之重写clone方法实现深... 查看详情

原型模式---prototype(代码片段)

...式:在Java中提供了clone()方法来实现对象的克隆,所以Prototype模式实现变得简单许多。实现条件:implementsCloneable接口重写clone()方法组成:分类:原型模式分为浅 查看详情

8创建型模式之原型模式

概念Prototype模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例。使用Prototype模式创建的实例,具有与原型一样的数据。1)由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身... 查看详情

object-c编程之道ios设计模式解析--原型模式

何为原型模式原型模式是一种简单的设计模式。客户端只奥抽象Prototype类。在运行时,抽象 Prototype子类的任何对象都可以按照客户端的一直被复制。因此,无需手工创建就可以复制同一类型的多个实例。何时使用原型模... 查看详情

一天学习一个设计模式之原型模式

原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。  原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。例如:有一张个人简历(此为具体... 查看详情

设计模式之原型模式

原型模式(prototype)为创建型对象模式,它是用原型实例来指定创建对象的类型的,并通过拷贝这些原型来创建新的对象。也就是说,这次我们创建新的对象和以前创建对象的方法有些不同,以前创建新的对象是用new方法作用于... 查看详情

设计模式之原型模式(代码片段)

原型模式——PrototypePattern原型模式:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。用于复制对象。 原型模式结构:  原型类Prototype(原型类,声明克隆自身的接口)  具体原型类ConcretePrototype(... 查看详情

java设计模式——原型模式(代码片段)

文章目录原型模式(Prototype)概念代码案例优缺点优点缺点:应用场景原型模式(Prototype)在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象&#x... 查看详情

原型模式

原型模式是创建类设计模式中最容易理解的一种设计模式,类图如下:原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件:实现Cloneable接口。在java语言有一个Cloneable接口,... 查看详情

源码时代java干货分享|带你了解原型模式_prototype

原型模式概述在java中创建一个对象通过new是非常繁琐的,需要创建检查权限,做一些数据准备等等,因此也会销毁系统性能,那么想要快快速简单的创建出对象,我们可以通过原型模式实现,以某个对象... 查看详情

原型模式

...式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件:实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类... 查看详情

原型模式(代码片段)

...式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件:实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类... 查看详情

再战设计模式之原型模式(代码片段)

原型模式(prototype)这个模式一般在工作中很少用,但是在框架里可能经常有,它是在什么情况下用呢?比如我们创建一个对象,需要10ms,在创建一个对象也需要10ms,这样就很耗时..举一个很简单的例子.小A在考试,做一份卷子需要一个小时... 查看详情