• 【创建型模式】原型模式


    一、原型模式概述

            原型(Prototype)模式的定义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。(对象创建型)

    •  工作原理
      • 将一个原型对象传给要发动创建的对象(即客户端对象),这个要发动创建的对象通过请求原型对象复制自己来实现创建过程。
      • 创建新对象(也称克隆对象)的工厂就是原型类自身,工厂方法由负责复制原型对象的克隆方法来实现。
      • 通过克隆方法所创建的对象是全新的对象,它们在内存中拥有新的地址,每个克隆对象都是独立的。
      • 通过不同的方式对克隆对象进行修改以后,可以得到一系列相似但不完全相同的对象。
    • 浅克隆与深克隆
      • 浅克隆:当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。
      • ​深克隆:除了对象本身被复制外,对象所包含的所有成员变量也将被复制。
    • 原型管理器
      • 将多个原型对象存储在一个集合中提供客户端使用,它是一个专门负责克隆对象的工厂,其中定义了一个集合用于存储原型对象,如果需要某个原型对象的一个克隆,可以通过复制集合中对应的原型对象来获得。
    • 原型模式的优缺点
      • 优点
        • 1.简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率;
        • 2.扩展性好;
        • 3.提供了简化的创建结构,原型模式中的产品的复制时通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品;
        • 4.可以使用深克隆的方式保存对象的状态,以便在需要的时候使用,可辅助实现撤销操作。
      • 缺点
        • 1.需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当已有对象的类进行改造时们需要修改源代码,违背了开闭原则;
        • 2.在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应得类都必须支持深克隆,实现起来可能会比较麻烦。
    • 适用环境
      • 1.创建新对象成本比较大,新对象可以通过复制已有对象来获得,如果相似对象,则可以对其成员变量稍作修改;
      • 2.系统要保存对象得状态,而对象得状态变化很小;
      • 3.需要便面使用分层次得工厂类来创建分层次得对象;
      • 4.ctrl+c->ctrl+v。

    二、代码实现

            原型模式包含三个角色:

    • 访问类(客户类):提出创建对象的请求,使用具体原型类中的 clone() 方法来复制新的对象。
    • 抽象原型(Prototype)角色:此角色定义了的具体原型类所需的实现的方法。也就是定义一个文件,说明一下它有被克隆复制的功能。
    • 具体原型(Concrete Prototype)角色:实现抽象原型角色的克隆接口。就是我们的文件实现了可以被复制的功能。

            我们会发现其实原型模式的核心就是Prototype(抽象原型),他需要继承Cloneable接口,并且重写Object类中的clone方法才能有复制粘贴的功能。

    2.1 demo

            2.1.1 抽象原型角色
    1. package prototype.demo;
    2. //抽象原型角色
    3. public interface Prototype {
    4. public Prototype clone();
    5. }
            2.1.2 具体原型角色
    1. package prototype.demo;
    2. //具体原型角色
    3. public class ConcretePrototype implements Prototype{
    4. private int dataInt=1;
    5. private A dataA=new A();
    6. public String toString() {
    7. return "ConcretePrototype"+"["+",dataInt"+dataInt
    8. +",dataA_address="+dataA
    9. +",dataA="+dataA.getChar_a()+
    10. "]";
    11. }
    12. public int getDataInt() {
    13. return dataInt;
    14. }
    15. public void setDataInt(int dataInt) {
    16. this.dataInt = dataInt;
    17. }
    18. public A getDataA() {
    19. return dataA;
    20. }
    21. public void setDataA(A dataA) {
    22. this.dataA = dataA;
    23. }
    24. //克隆方法 shallow
    25. public Prototype clone() {
    26. ConcretePrototype copy=new ConcretePrototype();
    27. copy.setDataInt(this.getDataInt());
    28. copy.setDataA(this.getDataA());
    29. return copy;
    30. }
    31. //克隆方法 deep
    32. public Prototype clone2() {
    33. ConcretePrototype copy=new ConcretePrototype();
    34. copy.setDataInt(this.getDataInt());
    35. A ta=new A();
    36. ta.setChar_a(this.getDataA().getChar_a());
    37. copy.setDataA(this.getDataA());
    38. return copy;
    39. }
    40. }
    1. package prototype.demo;
    2. //封装的方法
    3. public class A {
    4. char char_a;
    5. public char getChar_a() {
    6. return char_a;
    7. }
    8. public void setChar_a(char char_a) {
    9. this.char_a = char_a;
    10. }
    11. public A(char char_a) {
    12. super();
    13. this.char_a=char_a;
    14. }
    15. public A() {
    16. this.char_a='a';
    17. }
    18. }
            2.1.3 main方法实现原型模式(Client)
    1. package prototype.demo;
    2. public class Client {
    3. public static void main(String[] args) {
    4. // TODO 自动生成的方法存根
    5. /*ConcretePrototype p=new ConcretePrototype();
    6. ConcretePrototype copy=(ConcretePrototype) p.clone();
    7. ConcretePrototype copy2=(ConcretePrototype) p.clone();
    8. System.out.println(p.toString());
    9. System.out.println(copy.toString());
    10. System.out.println(copy2.toString());
    11. copy.setDataInt(2);
    12. A a=new A('b');
    13. copy.setDataA(a);
    14. System.out.println("-------------------------------");
    15. System.out.println(p.toString());
    16. System.out.println(copy.toString());
    17. System.out.println(copy2.toString());*/
    18. ConcretePrototype p=new ConcretePrototype();
    19. ConcretePrototype copy=(ConcretePrototype) p.clone2();
    20. ConcretePrototype copy2=(ConcretePrototype) p.clone2();
    21. System.out.println(p.toString());
    22. System.out.println(copy.toString());
    23. System.out.println(copy2.toString());
    24. copy.setDataInt(2);
    25. A a=new A('b');
    26. copy.setDataA(a);
    27. System.out.println("-------------------------------");
    28. System.out.println(p.toString());
    29. System.out.println(copy.toString());
    30. System.out.println(copy2.toString());
    31. }
    32. }
            2.4 UML图

    2.2 浅克隆

            2.2.1 抽象原型角色

            java.io.Serializable这个接口。

            2.2.2 具体原型角色
    1. package prototype.deepclone;
    2. import java.io.Serializable;
    3. //实现了Serializable这个接口
    4. public class Attachment implements Serializable{
    5. private String name;
    6. public String getName() {
    7. return name;
    8. }
    9. public void setName(String name) {
    10. this.name = name;
    11. }
    12. public void download() {
    13. System.out.println("下载附件,文件名为:"+name);
    14. }
    15. }
    1. package prototype.shallowclone;
    2. public class WeeklyLog implements Cloneable{
    3. //简化设计,定义一个附件
    4. private Attachment attachment;
    5. private String name;
    6. private String date;
    7. private String content;
    8. public Attachment getAttachment() {
    9. return attachment;
    10. }
    11. public void setAttachment(Attachment attachment) {
    12. this.attachment = attachment;
    13. }
    14. public String getName() {
    15. return name;
    16. }
    17. public void setName(String name) {
    18. this.name = name;
    19. }
    20. public String getDate() {
    21. return date;
    22. }
    23. public void setDate(String date) {
    24. this.date = date;
    25. }
    26. public String getContent() {
    27. return content;
    28. }
    29. public void setContent(String content) {
    30. this.content = content;
    31. }
    32. //使用clone()方法实现浅克隆
    33. @Override
    34. protected WeeklyLog clone(){
    35. // TODO 自动生成的方法存根
    36. try {
    37. return (WeeklyLog)super.clone();
    38. } catch (CloneNotSupportedException e) {
    39. // TODO 自动生成的 catch 块
    40. e.printStackTrace();
    41. return null;
    42. }
    43. }
    44. }
            2.2.3 Client
    1. package prototype.shallowclone;
    2. public class Client {
    3. public static void main(String[] args) {
    4. // TODO 自动生成的方法存根
    5. WeeklyLog obj=new WeeklyLog();
    6. Attachment att=new Attachment();
    7. att.setName("obj");
    8. obj.setAttachment(att);
    9. WeeklyLog copy=obj.clone();
    10. obj.getAttachment().download();
    11. copy.getAttachment().download();
    12. }
    13. }

    2.3 深克隆

            2.2.1 抽象原型角色

            java.io.Serializable这个接口。

            2.2.2 具体原型角色
    1. package prototype.deepclone;
    2. import java.io.Serializable;
    3. //实现了Serializable这个接口
    4. public class Attachment implements Serializable{
    5. private String name;
    6. public String getName() {
    7. return name;
    8. }
    9. public void setName(String name) {
    10. this.name = name;
    11. }
    12. public void download() {
    13. System.out.println("下载附件,文件名为:"+name);
    14. }
    15. }
    1. package prototype.deepclone;
    2. import java.io.*;
    3. public class WeeklyLog implements Serializable{
    4. //简化设计,定义一个附件
    5. private Attachment attachment;
    6. private String name;
    7. private String date;
    8. private String content;
    9. public Attachment getAttachment() {
    10. return attachment;
    11. }
    12. public void setAttachment(Attachment attachment) {
    13. this.attachment = attachment;
    14. }
    15. public String getName() {
    16. return name;
    17. }
    18. public void setName(String name) {
    19. this.name = name;
    20. }
    21. public String getDate() {
    22. return date;
    23. }
    24. public void setDate(String date) {
    25. this.date = date;
    26. }
    27. public String getContent() {
    28. return content;
    29. }
    30. public void setContent(String content) {
    31. this.content = content;
    32. }
    33. //使用序列化技术实现克隆
    34. protected WeeklyLog deepClone() throws IOException,ClassNotFoundException{
    35. // TODO 自动生成的方法存根
    36. //将对象写入流中
    37. ByteArrayOutputStream bao=new ByteArrayOutputStream();
    38. ObjectOutputStream oos=new ObjectOutputStream(bao);
    39. oos.writeObject(this);
    40. //将对象从流中取出
    41. ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());
    42. ObjectInputStream ois=new ObjectInputStream(bis);
    43. return (WeeklyLog)ois.readObject();
    44. }
    45. }
            2.2.3 Client
    1. package prototype.deepclone;
    2. public class Client {
    3. public static void main(String[] args) {
    4. // TODO 自动生成的方法存根
    5. WeeklyLog log_previous,log_new=null;
    6. log_previous=new WeeklyLog();//创建原型对象
    7. Attachment attachment=new Attachment();//创建附件对象
    8. attachment.setName("aaa");
    9. log_previous.setAttachment(attachment);//将附件添加到周报中
    10. try {
    11. log_new=log_previous.deepClone();//调用深克隆方法
    12. }catch(Exception e) {
    13. System.out.println("克隆失败!");
    14. }
    15. //比较周报
    16. System.out.println("周报是否相同?"+(log_previous==log_new));
    17. //比较附件
    18. System.out.println("附件是否相同?"+(log_previous.getAttachment()==log_new.getAttachment()));
    19. log_previous.getAttachment().download();
    20. log_new.getAttachment().download();
    21. }
    22. }

    三、代码结构图

  • 相关阅读:
    Python之socket简玩
    Spring中@Validated和@Valid区别是什么
    强化学习和近似动态规划的区别与联系是什么,他们俩是一回事吗
    安卓基础知识:Intent解析
    Runtime——KVC,KVO原理
    网络原理之TCP-IP地址 & 子网掩码
    计算机系统(12)----- 处理机调度
    解决下载 vtk-mpi4py-update-part2-53e6ce.diff 耗时太长的问题
    深入理解Java NIO:原理、应用与实战详解
    智能算法和人工智能算法,人工智能算法概念股票
  • 原文地址:https://blog.csdn.net/qq_45276194/article/details/137922959