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

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

    这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

    首先,既然原型模式需要创建当前对象的克隆,那么我们就不得不学习克隆(或者叫 拷贝)的知识了。

    拷贝分为 浅拷贝 和 深拷贝

    定义一个Car类(浅拷贝)

     1 package top.bigking.prototype;
     2 
     3 import java.util.Date;
     4 
     5 /**
     6  * @Author ABKing
     7  * @Date 2020/2/11 下午2:53
     8  * 浅拷贝
     9  **/
    10 public class Car implements Cloneable {
    11     private String name;
    12     private Date date;
    13 
    14     @Override
    15     protected Object clone() throws CloneNotSupportedException {
    16         return super.clone();
    17     }
    18 
    19     public Car() {
    20     }
    21 
    22     public Car(String name, Date date) {
    23         this.name = name;
    24         this.date = date;
    25     }
    26 
    27     public String getName() {
    28         return name;
    29     }
    30 
    31     public void setName(String name) {
    32         this.name = name;
    33     }
    34 
    35     public Date getDate() {
    36         return date;
    37     }
    38 
    39     public void setDate(Date date) {
    40         this.date = date;
    41     }
    42 }

    定义一个Car2类(深拷贝)

     1 package top.bigking.prototype;
     2 
     3 import java.util.Date;
     4 
     5 /**
     6  * @Author ABKing
     7  * @Date 2020/2/11 下午5:39
     8  * 深拷贝
     9  **/
    10 public class Car2 implements Cloneable {
    11     private String name;
    12     private Date date;
    13 
    14     @Override
    15     protected Object clone() throws CloneNotSupportedException {
    16         Object obj = super.clone();
    17         Car2 car = (Car2) obj;
    18         car.setDate((Date) this.date.clone());
    19         return obj;
    20     }
    21 
    22     public Car2() {
    23     }
    24 
    25     public Car2(String name, Date date) {
    26         this.name = name;
    27         this.date = date;
    28     }
    29 
    30     public String getName() {
    31         return name;
    32     }
    33 
    34     public void setName(String name) {
    35         this.name = name;
    36     }
    37 
    38     public Date getDate() {
    39         return date;
    40     }
    41 
    42     public void setDate(Date date) {
    43         this.date = date;
    44     }
    45 }

    测试:

     1 package top.bigking.prototype;
     2 
     3 import org.junit.Test;
     4 
     5 import java.util.Date;
     6 
     7 /**
     8  * @Author ABKing
     9  * @Date 2020/2/11 下午4:40
    10  **/
    11 public class TestPrototype {
    12     //浅拷贝
    13     @Test
    14     public void testShallowCopy() throws CloneNotSupportedException {
    15         Date date = new Date(11314211L);
    16         Car car1 = new Car("兰博基尼", date);
    17         Car car2 = (Car) car1.clone(); //拷贝
    18 
    19         System.out.println("第一辆车:" + car1 + car1.getName() + "-----" + car1.getDate());
    20         System.out.println("第二辆车:" + car2 + car2.getName() + "-----" + car2.getDate());
    21 
    22         date.setTime(4444524L);
    23 
    24         System.out.println("--------修改date后-------");
    25 
    26         System.out.println("第一辆车:" + car1 + car1.getName() + "-----" + car1.getDate());
    27         System.out.println("第二辆车:" + car2 + car2.getName() + "-----" + car2.getDate());
    28     }
    29     //深拷贝
    30     @Test
    31     public void testDeepCopy() throws CloneNotSupportedException {
    32         Date date = new Date(11314211L);
    33         Car2 car1 = new Car2("兰博基尼", date);
    34         Car2 car2 = (Car2) car1.clone(); //拷贝
    35 
    36         System.out.println("第一辆车:" + car1 + car1.getName() + "-----" + car1.getDate());
    37         System.out.println("第二辆车:" + car2 + car2.getName() + "-----" + car2.getDate());
    38 
    39         date.setTime(4444524L);
    40 
    41         System.out.println("--------修改date后-------");
    42 
    43         System.out.println("第一辆车:" + car1 + car1.getName() + "-----" + car1.getDate());
    44         System.out.println("第二辆车:" + car2 + car2.getName() + "-----" + car2.getDate());
    45     }
    46 }

    运行结果分别为:

    1 /usr/local/java/jdk1.8.0_231/bin/java -ea -Didea.test.cyclic.buffer.size=1048576 -javaagent:/usr/local/bin/idea-IU-193.5662.53/lib/idea_rt.jar=37975:/usr/local/bin/idea-IU-193.5662.53/bin -Dfile.encoding=UTF-8 -classpath /usr/local/bin/idea-IU-193.5662.53/lib/idea_rt.jar:/usr/local/bin/idea-IU-193.5662.53/plugins/junit/lib/junit5-rt.jar:/usr/local/bin/idea-IU-193.5662.53/plugins/junit/lib/junit-rt.jar:/usr/local/java/jdk1.8.0_231/jre/lib/charsets.jar:/usr/local/java/jdk1.8.0_231/jre/lib/deploy.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/cldrdata.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/dnsns.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/jaccess.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/jfxrt.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/localedata.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/nashorn.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/sunec.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/sunjce_provider.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/sunpkcs11.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/zipfs.jar:/usr/local/java/jdk1.8.0_231/jre/lib/javaws.jar:/usr/local/java/jdk1.8.0_231/jre/lib/jce.jar:/usr/local/java/jdk1.8.0_231/jre/lib/jfr.jar:/usr/local/java/jdk1.8.0_231/jre/lib/jfxswt.jar:/usr/local/java/jdk1.8.0_231/jre/lib/jsse.jar:/usr/local/java/jdk1.8.0_231/jre/lib/management-agent.jar:/usr/local/java/jdk1.8.0_231/jre/lib/plugin.jar:/usr/local/java/jdk1.8.0_231/jre/lib/resources.jar:/usr/local/java/jdk1.8.0_231/jre/lib/rt.jar:/home/king/IdeaProjects/GOF_23/target/test-classes:/home/king/IdeaProjects/GOF_23/target/classes:/home/king/maven/repository/junit/junit/4.10/junit-4.10.jar:/home/king/maven/repository/org/hamcrest/hamcrest-core/1.1/hamcrest-core-1.1.jar com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 top.bigking.prototype.TestPrototype,testShallowCopy
    2 第一辆车:top.bigking.prototype.Car@579bb367兰博基尼-----Thu Jan 01 11:08:34 CST 1970
    3 第二辆车:top.bigking.prototype.Car@255316f2兰博基尼-----Thu Jan 01 11:08:34 CST 1970
    4 --------修改date后-------
    5 第一辆车:top.bigking.prototype.Car@579bb367兰博基尼-----Thu Jan 01 09:14:04 CST 1970
    6 第二辆车:top.bigking.prototype.Car@255316f2兰博基尼-----Thu Jan 01 09:14:04 CST 1970
    7 
    8 Process finished with exit code 0

    可以很明显的看到,修改date后,时间并没有发生改变

    运行第二个JUnit测试:

    1 /usr/local/java/jdk1.8.0_231/bin/java -ea -Didea.test.cyclic.buffer.size=1048576 -javaagent:/usr/local/bin/idea-IU-193.5662.53/lib/idea_rt.jar=36785:/usr/local/bin/idea-IU-193.5662.53/bin -Dfile.encoding=UTF-8 -classpath /usr/local/bin/idea-IU-193.5662.53/lib/idea_rt.jar:/usr/local/bin/idea-IU-193.5662.53/plugins/junit/lib/junit5-rt.jar:/usr/local/bin/idea-IU-193.5662.53/plugins/junit/lib/junit-rt.jar:/usr/local/java/jdk1.8.0_231/jre/lib/charsets.jar:/usr/local/java/jdk1.8.0_231/jre/lib/deploy.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/cldrdata.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/dnsns.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/jaccess.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/jfxrt.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/localedata.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/nashorn.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/sunec.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/sunjce_provider.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/sunpkcs11.jar:/usr/local/java/jdk1.8.0_231/jre/lib/ext/zipfs.jar:/usr/local/java/jdk1.8.0_231/jre/lib/javaws.jar:/usr/local/java/jdk1.8.0_231/jre/lib/jce.jar:/usr/local/java/jdk1.8.0_231/jre/lib/jfr.jar:/usr/local/java/jdk1.8.0_231/jre/lib/jfxswt.jar:/usr/local/java/jdk1.8.0_231/jre/lib/jsse.jar:/usr/local/java/jdk1.8.0_231/jre/lib/management-agent.jar:/usr/local/java/jdk1.8.0_231/jre/lib/plugin.jar:/usr/local/java/jdk1.8.0_231/jre/lib/resources.jar:/usr/local/java/jdk1.8.0_231/jre/lib/rt.jar:/home/king/IdeaProjects/GOF_23/target/test-classes:/home/king/IdeaProjects/GOF_23/target/classes:/home/king/maven/repository/junit/junit/4.10/junit-4.10.jar:/home/king/maven/repository/org/hamcrest/hamcrest-core/1.1/hamcrest-core-1.1.jar com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 top.bigking.prototype.TestPrototype,testDeepCopy
    2 第一辆车:top.bigking.prototype.Car2@579bb367兰博基尼-----Thu Jan 01 11:08:34 CST 1970
    3 第二辆车:top.bigking.prototype.Car2@255316f2兰博基尼-----Thu Jan 01 11:08:34 CST 1970
    4 --------修改date后-------
    5 第一辆车:top.bigking.prototype.Car2@579bb367兰博基尼-----Thu Jan 01 09:14:04 CST 1970
    6 第二辆车:top.bigking.prototype.Car2@255316f2兰博基尼-----Thu Jan 01 11:08:34 CST 1970
    7 
    8 Process finished with exit code 0

    可以看到,时间已经发生了变化。

    什么时候会用到拷贝呢?

    答案是 当使用new关键字创建对象太耗时时,使用拷贝的方法可以大大加快速度

     1 package top.bigking.prototype;
     2 
     3 import org.junit.Test;
     4 
     5 import java.io.ObjectInputStream;
     6 
     7 /**
     8  * @Author ABKing
     9  * @Date 2020/2/13 下午5:39
    10  **/
    11 public class TestPrototype {
    12     //测试直接new的方式
    13     @Test
    14     public void testNew(){
    15         long start = System.currentTimeMillis();
    16         for (int i = 0; i < 1000; i++) {
    17             TestCar car = new TestCar();
    18         }
    19         long end = System.currentTimeMillis();
    20         System.out.println("使用new的方法总耗时:" + (end - start));
    21 
    22     }
    23     @Test
    24     public void testCopy() throws CloneNotSupportedException {
    25         long start = System.currentTimeMillis();
    26         TestCar car1 = new TestCar();
    27         for (int i = 0; i < 1000; i++) {
    28             TestCar car2 = (TestCar) car1.clone();
    29         }
    30         TestCar car2 = (TestCar) car1.clone();
    31         long end = System.currentTimeMillis();
    32         System.out.println("使用clone()的方法总耗时: " + (end - start));
    33     }
    34 }
    35 class TestCar implements Cloneable{
    36     public TestCar(){
    37         try {
    38             Thread.sleep(10); // 模拟创建对象的时间
    39         } catch (InterruptedException e) {
    40             e.printStackTrace();
    41         }
    42     }
    43 
    44     @Override
    45     protected Object clone() throws CloneNotSupportedException {
    46         return super.clone();
    47     }
    48 }

    运行第一个JUnit测试,执行结果如下:

    使用new的方法总耗时:10121

    运行第二个JUnit测试,执行结果如下:

    使用clone()的方法总耗时: 11

    可以看到,差距非常明显,使用clone()方法,几乎不耗时间

     当然,值得注意的是,当new非常耗时的时候,两者差距才很明显,如果把本例中的Thread.sleep(10)注释掉,两者所耗时均为0,几乎不耗时间。

    开发中的应用场景:

    原型模式一般很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。

    spring中bean对象的创建实际就是两种:单例模式和原型模式(当然,原型模式需要和工厂模式搭配起来)。

    金麟岂是池中物,一遇风云便化龙!
  • 相关阅读:
    国内代码托管平台(Git和SVN)
    搭建网络svn实战
    2016你一定要试试这8款原型设计工具
    Linux下查看用户列表
    详解Oracle DELETE和TRUNCATE 的区别
    Oracle 用户表空间查看、修改大小、设置自增长等
    win7电脑定时开机设置方法
    weblogic负载分发
    怎样实现一个数据库关系系统?
    选择数据库管理系统(DBMS)时主要考虑的因素
  • 原文地址:https://www.cnblogs.com/ABKing/p/12297398.html
Copyright © 2011-2022 走看看