前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >原型模式

原型模式

作者头像
千羽
发布2021-12-29 12:25:34
3090
发布2021-12-29 12:25:34
举报
文章被收录于专栏:程序员千羽程序员千羽
  • 1. 原型模式概述
  • 2. 原型模式的结构与实现
  • 3. 原型模式的应用实例
  • 4. 原型管理器
  • 5. 原型模式的优缺点与适用环境

代码托管

  • Gitee:https://gitee.com/nateshao/design-demo/tree/main/JavaDesignPatterns/07-prototype
  • Github:https://github.com/nateshao/design-demo/tree/main/JavaDesignPatterns/07-prototype

1. 原型模式概述

“通过复制一个原型对象得到多个与原型对象一模一样的新对象

定义:

原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象

  • 工作原理:将一个原型对象传给要发动创建的对象(即客户端对象),这个要发动创建的对象通过请求原型对象复制自己来实现创建过程
  • 创建新对象(也称为克隆对象)的工厂就是原型类自身,工厂方法由负责复制原型对象的克隆方法来实现
  • 通过克隆方法所创建的对象是全新的对象,它们在内存中拥有新的地址,每一个克隆对象都是独立的
  • 通过不同的方式对克隆对象进行修改以后,可以得到一系列相似但不完全相同的对象

2. 原型模式的结构与实现

原型模式的结构

原型模式包含以下3个角色:

  • Prototype(抽象原型类)
  • ConcretePrototype(具体原型类)
  • Client(客户类)

浅克隆与深克隆

浅克隆(Shallow Clone):当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。

**深克隆(Deep Clone):**除了对象本身被复制外,对象所包含的所有成员变量也将被复制。

通用的克隆实现方法

Java语言中的clone()方法和Cloneable接口

在Java语言中,提供了一个clone()方法用于实现浅克隆,该方法使用起来很方便,直接调用super.clone()方法即可实现克隆

浅克隆

WeeklyLog.java

代码语言:javascript
复制
package com.nateshao.prototype.shallowclone;

public class WeeklyLog implements Cloneable {
   // 为了简化设计和实现,假设一份工作周报中只有一个附件对象,
   // 实际情况中可以包含多个附件,可以通过List等集合对象来实现
   private Attachment attachment;
   private String name;
   private String date;
   private String content;

   public void setAttachment(Attachment attachment) {
      this.attachment = attachment;
   }

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

   public void setDate(String date) {
      this.date = date;
   }

   public void setContent(String content) {
      this.content = content;
   }

   public Attachment getAttachment() {
      return (this.attachment);
   }

   public String getName() {
      return (this.name);
   }

   public String getDate() {
      return (this.date);
   }

   public String getContent() {
      return (this.content);
   }

   //使用clone()方法实现浅克隆
   public WeeklyLog clone() {
      Object obj = null;
      try {
         obj = super.clone();
         return (WeeklyLog)obj;
      }
      catch(CloneNotSupportedException e) {
         System.out.println("不支持复制!");
         return null;
      }
   }
}

Attachment.java

代码语言:javascript
复制
package com.nateshao.prototype.shallowclone;

public class Attachment {
   private String name; //附件名

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

   public String getName() {
      return this.name;
   }

   public void download() {
      System.out.println("下载附件,文件名为" + name);
   }
}

Client.java

代码语言:javascript
复制
package com.nateshao.prototype.shallowclone;

public class Client {
   public static void main(String args[]) {
      WeeklyLog log_previous, log_new;
      log_previous = new WeeklyLog();          //创建原型对象
      Attachment attachment = new Attachment();    //创建附件对象
      log_previous.setAttachment(attachment);       //将附件添加到周报中
      log_new = log_previous.clone();             //调用克隆方法创建克隆对象
      //比较周报
      System.out.println("周报是否相同? " + (log_previous == log_new));
      //比较附件
      System.out.println("附件是否相同? " + (log_previous.getAttachment() == log_new.getAttachment()));
   }
}

深克隆

WeeklyLog.java

代码语言:javascript
复制
package com.nateshao.prototype.deepclone;

import java.io.*;

/**
 * @date Created by 邵桐杰 on 2021/10/14 21:59
 * @微信公众号 程序员千羽
 * @个人网站 www.nateshao.cn
 * @博客 https://nateshao.gitee.io
 * @GitHub https://github.com/nateshao
 * @Gitee https://gitee.com/nateshao
 * Description:
 */
public class WeeklyLog implements Serializable {
    private Attachment attachment;
    private String name;
    private String date;
    private String content;

    public void setAttachment(Attachment attachment) {
        this.attachment = attachment;
    }

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

    public void setDate(String date) {
        this.date = date;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Attachment getAttachment() {
        return (this.attachment);
    }

    public String getName() {
        return (this.name);
    }

    public String getDate() {
        return (this.date);
    }

    public String getContent() {
        return (this.content);
    }

    //使用序列化技术实现深克隆
    public WeeklyLog 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 (WeeklyLog)ois.readObject();
    }
}

Attachment.java

代码语言:javascript
复制
package com.nateshao.prototype.deepclone;

import java.io.Serializable;

/**
 * @date Created by 邵桐杰 on 2021/10/14 22:00
 * @微信公众号 程序员千羽
 * @个人网站 www.nateshao.cn
 * @博客 https://nateshao.gitee.io
 * @GitHub https://github.com/nateshao
 * @Gitee https://gitee.com/nateshao
 * Description:
 */

public class Attachment implements Serializable {
    private String name; //附件名

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

    public String getName() {
        return this.name;
    }

    public void download() {
        System.out.println("下载附件,文件名为" + name);
    }
}

Client.java

代码语言:javascript
复制
package com.nateshao.prototype.deepclone;

/**
 * @date Created by 邵桐杰 on 2021/10/14 22:00
 * @微信公众号 程序员千羽
 * @个人网站 www.nateshao.cn
 * @博客 https://nateshao.gitee.io
 * @GitHub https://github.com/nateshao
 * @Gitee https://gitee.com/nateshao
 * Description:
 */
public class Client {
    public static void main(String args[]) {
        WeeklyLog log_previous, log_new = null;
        log_previous = new WeeklyLog();           //创建原型对象
        Attachment attachment = new Attachment();   //创建附件对象
        log_previous.setAttachment(attachment);     //将附件添加到周报中
        try {
            log_new = log_previous.deepClone(); //调用深克隆方法创建克隆对象
        }
        catch(Exception e) {
            System.err.println("克隆失败!");
        }
        //比较周报
        System.out.println("周报是否相同? " + (log_previous == log_new));
        //比较附件
        System.out.println("附件是否相同? " + (log_previous.getAttachment() == log_new.getAttachment()));
    }
}

3. 原型模式的应用实例

实例说明

“在使用某OA系统时,有些岗位的员工发现他们每周的工作都大同小异,因此在填写工作周报时很多内容都是重复的,为了提高工作周报的创建效率,大家迫切希望有一种机制能够快速创建相同或者相似的周报,包括创建周报的附件。 试使用原型模式对该OA系统中的工作周报创建模块进行改进。

实例类图

工作周报创建模块结构图:浅克隆

工作周报对象被成功复制,但是附件对象并没有复制,实现了浅克隆

深克隆解决方案

工作周报类WeeklyLog和附件类Attachment实现Serializable接口

修改工作周报类WeeklyLog的clone()方法

  1. WeeklyLog: 具体原型类
  2. Attachment: 具体原型类
  3. Client

周报是否相同?false

附件是否相同?false

工作周报对象和附件对象都成功复制,实现了深克隆

4. 原型管理器

“定义:原型管理器(Prototype Manager)将多个原型对象存储在一个集合中供客户端使用,它是一个专门负责克隆对象的工厂,其中定义了一个集合用于存储原型对象,如果需要某个原型对象的一个克隆,可以通过复制集合中对应的原型对象来获得

结构:

带原型管理器的原型模式

实现

代码语言:javascript
复制
import java.util.*;

public class PrototypeManager {
    private Hashtable prototypeTable=new Hashtable();  //使用Hashtable存储原型对象
    public PrototypeManager() {
        prototypeTable.put("A", new ConcretePrototypeA());
        prototypeTable.put("B", new ConcretePrototypeB());
    }
   
    public void add(String key, Prototype prototype) {
        prototypeTable.put(key,prototype);
    } 

    public Prototype get(String key) {
        Prototype clone = null;
        clone = ((Prototype) prototypeTable.get(key)).clone(); //通过克隆方法创建新对象
        return clone;
    }
}

5. 原型模式的优缺点与适用环境

模式优点

  1. 简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率
  2. 扩展性较好
  3. 提供了简化的创建结构,原型模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品
  4. 可以使用深克隆的方式保存对象的状态,以便在需要的时候使用,可辅助实现撤销操作

模式缺点

  1. 需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时,需要修改源代码,违背了开闭原则
  2. 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦

模式适用环境

  1. 创建新对象成本较大,新对象可以通过复制已有对象来获得,如果是相似对象,则可以对其成员变量稍作修改
  2. 系统要保存对象的状态,而对象的状态变化很小
  3. 需要避免使用分层次的工厂类来创建分层次的对象
  4. Ctrl + C -> Ctrl + V
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 千羽的编程时光 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 原型模式概述
  • 2. 原型模式的结构与实现
  • 3. 原型模式的应用实例
  • 4. 原型管理器
  • 5. 原型模式的优缺点与适用环境
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档