zoukankan      html  css  js  c++  java
  • 设计模式之原型模式

    原型模式——PrototypePattern

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

    用于复制对象。

    原型模式结构:

      原型类Prototype(原型类,声明克隆自身的接口)

      具体原型类ConcretePrototype(具体的原型类,继承原型类,实现克隆自身的操作)

    关于复制分为浅复制深复制

      浅复制:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。(引用类型会共享)

      深复制:对于旧对象的字段是引用类型,新建一个新的同类型的引用对象,将旧字段的引用类型中的内容赋给新建的引用对象,再将新建的引用对象赋给复制的对象。(就是复制所有的东西,引用类型的会新建)

     

    Java中实现克隆的方法:

    •     1、新建原型类,声明克隆接口,在具体原型类中引用其接口,实现具体克隆操作
          • 原型类
            public interface IExprience {
                public Object Clone();
            }
          • 具体原型类
            public class Experience implements IExprience{
                private String educationBackground;
                private String skills;
            
                public void setExperience(String educationBackground,String skills) {
                    this.educationBackground=educationBackground;
                    this.skills=skills;
                }public Object Clone()
                {
                    Experience experience=new Experience();
                    experience.setExperience(this.educationBackground,this.skills);
                    return experience;
                }
            }
          • 主函数
                    Experience experience=new Experience();
                    experience.setExperience("专科","C#");
                    Experience experience1=(Experience) experience.Clone();
                    System.out.println(experience);
                    System.out.println(experience1);    
    •     2、不声明原型类,直接在具体类中实现clone操作
          • 具体类
            public class Experience{
                private String educationBackground;
                private String skills;
            
                public void setExperience(String educationBackground,String skills) {
                    this.educationBackground=educationBackground;
                    this.skills=skills;
                }
                public Experience Clone()
                {
                    Experience experience=new Experience();
                    experience.setExperience(this.educationBackground,this.skills);
                    return experience;
                }
            }
    •     3、具体类中继承Java的Cloneable接口 调用super.clone()方法
          •       
             1 public class ExperienceDeepCopy implements Cloneable{//这里继承了Cloneable接口
             2     private String educationBackground;
             3     private String skills;
             4 
             5     public void setExperience(String educationBackground,String skills) {
             6         this.educationBackground=educationBackground;
             7         this.skills=skills;
             8     }
             9 
            10     @Override
            11     public String toString() {
            12         return educationBackground+skills;
            13     }
            14     public ExperienceDeepCopy Clone()
            15     {
            16         try {
            17             return (ExperienceDeepCopy) super.clone();//这里使用了Java提供的clone方法,这个clone方法是浅复制,需要放在try catch中
            18         }
            19         catch (Exception e)
            20         {
            21             e.printStackTrace();
            22             return null;
            23         }
            24     }
            25 }

    Java 中的super.clone():

     我们知道该clone()方法是使用Object类的clone()方法,但是该方法存在一个缺陷,它并不会将对象的所有属性全部拷贝过来,而是有选择性的拷贝,基本规则如下:

    •       1、 基本类型
    •          如果变量是基本很类型,则拷贝其值,比如int、float等。
    •       2、 对象
    •          如果变量是一个实例对象,则拷贝其地址引用,也就是说此时新对象与原来对象是公用该实例变量。
    •       3、 String字符串
    •          若变量为String字符串,则拷贝其地址引用。但是在修改时,它会从字符串池中重新生成一个新的字符串,原有紫都城对象保持不变。

     

    深复制的实现:

    1   public ResumeDeepCopy clone() {
    2         ExperienceDeepCopy experience=this.experience.Clone();
    3         return new ResumeDeepCopy(this.name,this.age,experience);
    4     }

      深复制首先需要在字段所用的引用类型的类中增加一个Clone方法。普通字段直接使用原有的字段新建对象,引用对象需要通过该对象的Clone方法先复制出一个新对象,再将这个新的引用字段来构造新的对象。

    浅复制实现原型模式:

      工作经验类 Experience

     1 public class Experience{
     2     private String educationBackground;
     3     private String skills;
     4 
     5     public void setExperience(String educationBackground,String skills) {
     6         this.educationBackground=educationBackground;
     7         this.skills=skills;
     8     }
     9 
    10     @Override
    11     public String toString() {
    12         return educationBackground+skills;
    13     }
    14   }
    15 }

      

      简历类Resume 

     1 package PrototypePattern;
     2 
     3 public class Resume implements Cloneable{
     4     private String name;
     5     private int age;
     6     private Experience experience;
     7     public Resume(String name, int age)
     8     {
     9         this.name=name;
    10         this.age=age;
    11         this.experience=new Experience();
    12     }
    13     public void setAge(int age) {
    14         this.age = age;
    15     }
    16 
    17     public void setName(String name) {
    18         this.name = name;
    19     }
    20 
    21     public void setExperience(String educationBackground,String skills) {
    22         this.experience.setExperience(educationBackground,skills);
    23     }
    24 
    25     @Override
    26     public String toString() {
    27         return "name:"+name+"  age:"+age+"  experience:"+experience;
    28     }
    29     public Resume clone() {
    30         try {
    31             return (Resume) super.clone();
    32         }
    33         catch (Exception e)
    34         {
    35             System.out.println(e);
    36             return null;
    37         }
    38 
    39     }
    40 }

      主函数

     1 public class Client {
     2     public static void main(String[] args) {
     3         //Copy
     4         Resume resume=new Resume("test",20);
     5         resume.setExperience("本科","C++");
     6         Resume resume2= resume.clone();
     7         System.out.println("resume and resume2");
     8         System.out.println(resume);
     9         System.out.println(resume2);
    10         System.out.println();
    11         System.out.println("resume and modified resume2");
    12         resume2.setAge(18);
    13         resume2.setName("copy");
    14         resume2.setExperience("专科","C#");
    15         System.out.println(resume);
    16         System.out.println(resume2);
    17     }
    18 }

      结果:

          

        可见当改变Experience时,也会改变原对象的值。

    深复制实现原型模式:

      经验类 ExperienceDeepCopy 

     1 public class ExperienceDeepCopy implements Cloneable{
     2     private String educationBackground;
     3     private String skills;
     4 
     5     public void setExperience(String educationBackground,String skills) {
     6         this.educationBackground=educationBackground;
     7         this.skills=skills;
     8     }
     9 
    10     @Override
    11     public String toString() {
    12         return educationBackground+skills;
    13     }
    14     public ExperienceDeepCopy Clone()
    15     {
    16         try {
    17             return (ExperienceDeepCopy) super.clone();
    18         }
    19         catch (Exception e)
    20         {
    21             e.printStackTrace();
    22             return null;
    23         }
    24     }
    25 }

      

      简历类 ResumeDeepCopy

     1 public class ResumeDeepCopy{
     2     private String name;
     3     private int age;
     4     private ExperienceDeepCopy experience;
     5     public ResumeDeepCopy(String name, int age)
     6     {
     7         this.name=name;
     8         this.age=age;
     9         this.experience=new ExperienceDeepCopy();
    10     }
    11     private ResumeDeepCopy(String name, int age, ExperienceDeepCopy experience)
    12     {
    13         this.name=name;
    14         this.age=age;
    15         this.experience=experience;
    16     }
    17     public void setExperience(String educationBackground,String skills) {
    18         this.experience.setExperience(educationBackground,skills);
    19     }
    20     public void setAge(int age) {
    21         this.age = age;
    22     }
    23 
    24     public void setName(String name) {
    25         this.name = name;
    26     }
    27 
    28     @Override
    29     public String toString() {
    30         return "name:"+name+"  age:"+age+"  experience:"+experience;
    31     }
    32 
    33     public ResumeDeepCopy clone() {
    34         ExperienceDeepCopy experience=this.experience.Clone();
    35         return new ResumeDeepCopy(this.name,this.age,experience);
    36     }
    37 }

      主函数

     1 public class Client {
     2     public static void main(String[] args) {
     3         //DeepCopy
     4         System.out.println();
     5         ResumeDeepCopy resumeDeepCopy=new ResumeDeepCopy("test",20);
     6         resumeDeepCopy.setExperience("本科","C++");
     7         ResumeDeepCopy resumeDeepCopy2=resumeDeepCopy.clone();
     8         System.out.println("resumeDeepCopy and resumeDeepCopy2");
     9         System.out.println(resumeDeepCopy);
    10         System.out.println(resumeDeepCopy2);
    11         System.out.println();
    12         System.out.println("resumeDeepCopy and modified resumeDeepCopy2");
    13         resumeDeepCopy2.setAge(18);
    14         resumeDeepCopy2.setName("copy");
    15         resumeDeepCopy2.setExperience("专科","C#");
    16         System.out.println(resumeDeepCopy);
    17         System.out.println(resumeDeepCopy2);
    18     }
    19 }

      结果截图  

            

    深复制与浅复制参考文章:https://www.cnblogs.com/qlky/p/7348353.html

    原型模式相关代码:https://github.com/lancelee98/DesignPattern/tree/master/src/PrototypePattern

       

  • 相关阅读:
    IaaS、PaaS、SaaS
    hyper-V 配置
    解决linux下创建用户时出现Creating mailbox file: File exists
    iframe层级关系调用
    js,jq新增元素 ,on绑定事件无效
    js中!和!!的区别与用法
    form表单禁止button 提交
    Thinkphp5终端创建控制器和模型
    TP5的目录常量和路径
    sublime安装package controlller
  • 原文地址:https://www.cnblogs.com/lancelee98/p/10285535.html
Copyright © 2011-2022 走看看