博客信息

原型模式Prototype(创建模式)

发布时间:『 2019-03-21 23:54』  博客类别:23种设计模式  阅读(701)


  • 术语

    prototype:原型

    clone:克隆

  • 案例

    需求:将一只名字为杰克、性别为母的绵羊克隆10份;

    要求每只绵羊的属性、性别都一致;

    • 使用前

    package com.javaxl.design.prototype.before;

    /**
    * @author 小李飞刀
    * @site www.javaxl.com
    * @company
    * @create  2020-02-22 10:45
    */
    public class Sheep {
      private String name;
      private String sex;

      public Sheep(String name, String sex) {
          this.name = name;
          this.sex = sex;
      }

      public String getName() {
          return name;
      }

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

      public String getSex() {
          return sex;
      }

      public void setSex(String sex) {
          this.sex = sex;
      }

      @Override
      public String toString() {
          return "Sheep{" +
                  "name='" + name + '\'' +
                  ", sex='" + sex + '\'' +
                  '}';
      }
    }


    package com.javaxl.design.prototype.before;

    /**
    * @author 小李飞刀
    * @site www.javaxl.com
    * @company
    * @create  2020-02-22 10:46
    *
    * 将一只名字为杰克、性别为母的绵羊克隆10份;
    * 要求每只绵羊的属性、性别都一致;
    *
    * 弊端:无法将当前的状态进行复制
    */
    public class Client {
      public static void main(String[] args) {
          Sheep sheep1 = new Sheep("杰西", "母");
          Sheep sheep2 = new Sheep("杰西", "母");
          Sheep sheep3 = new Sheep("杰西", "母");
          Sheep sheep4 = new Sheep("杰西", "母");
          Sheep sheep5 = new Sheep("杰西", "母");
          Sheep sheep6 = new Sheep("杰西", "母");
          Sheep sheep7 = new Sheep("杰西", "母");
          Sheep sheep8 = new Sheep("杰西", "母");
          Sheep sheep9 = new Sheep("杰西", "母");
          Sheep sheep10 = new Sheep("杰西", "母");

    //       此时我要一只名为杰瑞的绵羊,其它绵羊属性与杰西一致;
    //       那么按照这种设计,只能这么创建所需的绵羊
    //       这种方式创建,目前只有两个属性问题不大,如果绵羊类有十几二十甚至更多的属性,那么是非常不方便的
          Sheep sheep11 = new Sheep("杰瑞", "母");

      }
    }

    • 使用后

package com.javaxl.design.prototype.after;

/**
* @author 小李飞刀
* @site www.javaxl.com
* @company
* @create  2020-02-22 10:45
*
* 使用原型设计模式进行设计
*/
public class Sheep implements Cloneable{
  private String name;
  private String sex;

  public Sheep(String name, String sex) {
      this.name = name;
      this.sex = sex;
  }

  public String getName() {
      return name;
  }

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

  public String getSex() {
      return sex;
  }

  public void setSex(String sex) {
      this.sex = sex;
  }

  @Override
  public String toString() {
      return "Sheep{" +
              "name='" + name + '\'' +
              ", sex='" + sex + '\'' +
              '}';
  }

  @Override
  protected Object clone() throws CloneNotSupportedException {
      Object obj = super.clone();
      System.out.println("被克隆了...");
      return obj;
  }
}


package com.javaxl.design.prototype.after;

/**
* @author 小李飞刀
* @site www.javaxl.com
* @company
* @create  2020-02-22 10:46
*
* 将一只名字为杰克、性别为母的绵羊克隆10份;
* 要求每只绵羊的属性、性别都一致;
*
*   使用原型设计模式进行设计后的测试
*/
public class Client {
  public static void main(String[] args) throws Exception{
      Sheep sheep1 = new Sheep("杰西", "母");
      Sheep sheep2 = (Sheep) sheep1.clone();
      Sheep sheep3 = (Sheep) sheep1.clone();
      Sheep sheep4 = (Sheep) sheep1.clone();
      Sheep sheep5 = (Sheep) sheep1.clone();
      Sheep sheep6 = (Sheep) sheep1.clone();
      Sheep sheep7 = (Sheep) sheep1.clone();
      Sheep sheep8 = (Sheep) sheep1.clone();
      Sheep sheep9 = (Sheep) sheep1.clone();
      Sheep sheep10 = (Sheep) sheep1.clone();
      System.out.println(sheep1);
      System.out.println(sheep2);

//       此时我要一只名为杰瑞的绵羊,其它绵羊属性与杰西一致;
//       按照原型设计模式,调用方Client类无需查找杰西相同部分的属性,只需变动差异部分属性进行克隆即可;
//       这种设计,目前只有两个属性使用起来感觉没多大区别,如果绵羊类有十几二十甚至更多的属性,那么感觉非常明显
      sheep1.setName("杰瑞");//其它的属性不需要去关注
      Sheep sheep11 = (Sheep) sheep1.clone();
      System.out.println(sheep11);
  }
}

结论:从对象创建的角度上来说,原型模式设计让相似的类实例创建更加的便捷

  • 深层次的使用

    • 浅拷贝

    package com.javaxl.design.prototype.light;

    /**
    * @author 小李飞刀
    * @site www.javaxl.com
    * @company
    * @create  2020-02-22 10:45
    *
    * 使用原型设计模式进行设计
    */
    public class Sheep implements Cloneable{
      private String name;
      private String sex;
      private Sheep friend;

      public Sheep(String name, String sex) {
          this.name = name;
          this.sex = sex;
      }

      public String getName() {
          return name;
      }

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

      public String getSex() {
          return sex;
      }

      public void setSex(String sex) {
          this.sex = sex;
      }

      public Sheep getFriend() {
          return friend;
      }

      public void setFriend(Sheep friend) {
          this.friend = friend;
      }

      @Override
      public String toString() {
          return "Sheep{" +
                  "name='" + name + '\'' +
                  ", sex='" + sex + '\'' +
                  ", friend=" + friend +
                  '}';
      }

      @Override
      protected Object clone() throws CloneNotSupportedException {
          Object obj = super.clone();
          System.out.println("被克隆了...");
          return obj;
      }
    }

    浅拷贝特点:对象中实例变量,如果是引用变量,不会重新开辟空间

    • 深拷贝

      • 方式一

      package com.javaxl.design.prototype.deep.one;

      /**
      * @author 小李飞刀
      * @site www.javaxl.com
      * @company
      * @create  2020-02-22 10:45
      * <p>
      * 使用原型设计模式进行设计
      */
      public class Sheep implements Cloneable {
        private String name;
        private String sex;
        private Sheep friend;
        private Sheep boyFriend;

        public Sheep(String name, String sex) {
            this.name = name;
            this.sex = sex;
        }

        public String getName() {
            return name;
        }

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

        public String getSex() {
            return sex;
        }

        public void setSex(String sex) {
            this.sex = sex;
        }

        public Sheep getFriend() {
            return friend;
        }

        public void setFriend(Sheep friend) {
            this.friend = friend;
        }

        public Sheep getBoyFriend() {
            return boyFriend;
        }

        public void setBoyFriend(Sheep boyFriend) {
            this.boyFriend = boyFriend;
        }

        @Override
        public String toString() {
            return "Sheep{" +
                    "name='" + name + '\'' +
                    ", sex='" + sex + '\'' +
                    ", friend=" + friend +
                    '}';
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            Object obj = super.clone();
            if (obj == null) {
                return obj;
            } else {
                //       被克隆出来的绵羊(目前这只绵羊的朋友还是本体的朋友)
                Sheep sheep = (Sheep) obj;
      //       将本体的朋友也克隆一份出来,给克隆羊
                Sheep friend = this.getFriend();
                if (friend !=null){
                    sheep.setFriend((Sheep) friend.clone());
                }
                return sheep;
            }
        }
      }


      package com.javaxl.design.prototype.deep.one;

      /**
      * @author 小李飞刀
      * @site www.javaxl.com
      * @company
      * @create  2020-02-22 10:46
      * <p>
      * 将一只名字为杰克、性别为母的绵羊克隆10份;
      * 要求每只绵羊的属性、性别都一致;
      * <p>
      * 使用原型设计模式进行设计后的测试
      */
      public class Client {
        public static void main(String[] args) throws Exception {
            Sheep sheep1 = new Sheep("杰西", "母");
            Sheep friend_jiexi = new Sheep("杰西的朋友", "公");
            Sheep boyFriend_jiexi = new Sheep("杰西的男朋友", "公");
            sheep1.setFriend(friend_jiexi);
            sheep1.setBoyFriend(boyFriend_jiexi);
            Sheep sheep2 = (Sheep) sheep1.clone();


            System.out.println("第1只叫杰西的绵羊的朋友:" + sheep1.getFriend().hashCode());
            System.out.println("第2只叫杰西的绵羊的朋友:" + sheep2.getFriend().hashCode());

            System.out.println("第1只叫杰西的绵羊的男朋友:" + sheep1.getBoyFriend().hashCode());
            System.out.println("第2只叫杰西的绵羊的男朋友:" + sheep2.getBoyFriend().hashCode());

        }
      }


小李飞刀_设计模式



    • 方式二

package com.javaxl.design.prototype.deep.two;

import java.io.*;

/**
* @author 小李飞刀
* @site www.javaxl.com
* @company
* @create  2020-02-22 10:45
*
* 使用原型设计模式进行设计
*/
public class Sheep implements Cloneable,Serializable{
  private String name;
  private String sex;
  private Sheep friend;
  private Sheep boyFriend;

  public Sheep getBoyFriend() {
      return boyFriend;
  }

  public void setBoyFriend(Sheep boyFriend) {
      this.boyFriend = boyFriend;
  }

  public Sheep(String name, String sex) {
      this.name = name;
      this.sex = sex;
  }

  public String getName() {
      return name;
  }

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

  public String getSex() {
      return sex;
  }

  public void setSex(String sex) {
      this.sex = sex;
  }

  public Sheep getFriend() {
      return friend;
  }

  public void setFriend(Sheep friend) {
      this.friend = friend;
  }

  @Override
  public String toString() {
      return "Sheep{" +
              "name='" + name + '\'' +
              ", sex='" + sex + '\'' +
              ", friend=" + friend +
              '}';
  }

  @Override
  protected Object clone() throws CloneNotSupportedException {
      Object obj = super.clone();
      System.out.println("被克隆了...");
      return obj;
  }

  protected Object deepClone() throws CloneNotSupportedException, IOException, ClassNotFoundException {
//       序列化
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
//       获取对象输出流
      ObjectOutputStream oos = new ObjectOutputStream(bos);
//       将当前的对象
      oos.writeObject(this);

//       反序列化
      ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
      Object obj = ois.readObject();
      return obj;
  }
}


public class Client {
  public static void main(String[] args) throws Exception {
      Sheep sheep1 = new Sheep("杰西", "母");
      Sheep friend_jiexi = new Sheep("杰西的朋友", "公");
      Sheep boyFriend_jiexi = new Sheep("杰西的男朋友", "公");
      sheep1.setFriend(friend_jiexi);
      sheep1.setBoyFriend(boyFriend_jiexi);
      Sheep sheep2 = (Sheep) sheep1.deepClone();

      System.out.println("第1只叫杰西的绵羊的朋友:" + sheep1.getFriend().hashCode());
      System.out.println("第2只叫杰西的绵羊的朋友:" + sheep2.getFriend().hashCode());

      System.out.println("第1只叫杰西的绵羊的男朋友:" + sheep1.getBoyFriend().hashCode());
      System.out.println("第2只叫杰西的绵羊的男朋友:" + sheep2.getBoyFriend().hashCode());

  }
}

小李飞刀_设计模式



结论:推荐使用深拷贝的第二种方式

  • 注意事项和细节

    • 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率

    • 不用重新初始化对象,而是动态地获得对象运行时的状态

    • 如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码

缺点: 1、需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则 2、实现深克隆的时候可能需要比较复杂的代码


over......


关键字:     设计模式  

备案号:湘ICP备19000029号

Copyright © 2018-2019 javaxl晓码阁 版权所有