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对象的创建实际就是两种:单例模式和原型模式(当然,原型模式需要和工厂模式搭配起来)。

    金麟岂是池中物,一遇风云便化龙!
  • 相关阅读:
    网页加速的14条优化法则 网站开发与优化
    .NET在后置代码中输入JS提示语句(背景不会变白)
    C语言变量声明内存分配
    SQL Server Hosting Toolkit
    An established connection was aborted by the software in your host machine
    C语言程序设计 2009春季考试时间和地点
    C语言程序设计 函数递归调用示例
    让.Net 程序脱离.net framework框架运行
    C语言程序设计 答疑安排(2009春季 110周) 有变动
    软件测试技术,软件项目管理 实验时间安排 2009春季
  • 原文地址:https://www.cnblogs.com/ABKing/p/12297398.html
Copyright © 2011-2022 走看看