zoukankan      html  css  js  c++  java
  • 设计模式总纲——原型设计模式

       接上文,在小陈合理的推广下,小陈的铺货量也是越来越大,越来越多,订单数量也是越来越多,大到上市公司,运动品牌专卖店,小到街边饰品小店等都来向小陈这边进货,但是随着订单的越来越多,现在每天的订单量都要将近10万量的计数,这时候一件让小陈头疼的事情来了,因为订单量过于多,现在小陈那边的出单机的速率已经跟不上了,因为原本出单机是一单单的打出来的,但是因为订单量过于庞大,速度实在跟不上了,而且小陈认真的观察了一下,订单的格式都是差不多的,都是订单时间,订单数量,订单的产品信息,预定公司的信息,基本上都是信息都是大同小异,我们先来看看街边小店的订单格式:

     1 public class OrderInfo {
     2     private String shopName;
     3     
     4     private String shopAddr;
     5     
     6     private String shopMobile;
     7     
     8     private String productName;
     9     
    10     private String productNumber;
    11 }//因为篇幅原因,setter/getter方法就不写了

    街边小店的订单格式比较简单,就基本信息和地址就是了,但是别看这种街边小店,现在有将近3K家小店跟小陈的公司有合作,每个月的营收可不少,有的时候小店的名字、地址、手机一样,就产品和数量不一样,又要重新生成一个订单,有的是小店的开了分店,地址不一样,但是其他的信息又一样,但是每个订单新生成的速度忒慢(如果每个订单都要生成,既浪费虚拟机的性能,而且每次填写相同的信息也要花费很多时间),这个时候,小陈想既然都一样,干脆复制得了,然后再重新填上区别的信息,这样就可以一个订单范本多家公司使用了。(大家可以想想为什么这里不用工厂模式来生成订单?)

      接下来我们就来看看怎么来进行复制:

     1 public class OrderInfo implements Cloneable{
     2     private String shopName;
     3     private String shopAddr;
     4     private String shopMobile;
     5     private String productName;
     6     private String productNumber;
     7 
     8     @Override
     9     protected Object clone() {
    10         try {
    11             return super.clone();
    12         } catch (CloneNotSupportedException e) {
    13             e.printStackTrace();
    14         }
    15         return null;
    16     }
    17 }//因为篇幅原因,setter/getter方法就不写了

    在这里OrderInfo必须实现Cloneable,让虚拟机知道该对象是可复制的,在这里必须说明一点,clone对象不是Cloneable中的方法,如果我们点进源代码里面看的话,会发现这个接口是个空接口,那这个clone方法是哪里来的呢?Java里面所有的对象都继承自Object,所以clone方法是Object对象中的方法,我们这里是重写了他的方法。好了,这样的话,我们来看看客户端来怎么生成,一家小店有两家分店,除了地址其他的信息都一样的订单了。

     1     @Test
     2     public void clien() {
     3         OrderInfo orderInfo = new OrderInfo("饰品小店", "北京王府井大街", "13888888888", "骑士徽章", "10000");
     4         
     5         OrderInfo cloneInfo = (OrderInfo)orderInfo.clone();
     6         
     7         cloneInfo.setShopAddr("北京王府井大街2号");
     8         
     9         System.out.println(orderInfo);
    10         System.out.println(cloneInfo);
    11     }

    OrderInfo [shopName=饰品小店, shopAddr=北京王府井大街, shopMobile=13888888888, productName=骑士徽章, productNumber=10000]
    OrderInfo [shopName=饰品小店, shopAddr=北京王府井大街2号, shopMobile=13888888888, productName=骑士徽章, productNumber=10000]

    这里的话,我们可以看到除了店面的地址不一样,其他的信息全部一样了,这样子就省去了很多成本了,订单的生产速度也快了不止一个级别,小陈非常开心,但是这个时候,订单出单员小A发现了个问题了,当订单是街边小店的订单的时候,订单会没有问题,但是当是上市公司的订单,或者品牌大店的订单的时候,出单就会有问题,小陈观察了一下,原来上市集团的大单的订单格式是下面这种方式的:

     1 public class OrderInfo implements Cloneable{
     2     private Product productInfo;
     3     private Company company;
     4     
     5     @Override
     6     protected Object clone() {
     7         try {
     8             return super.clone();
     9         } catch (CloneNotSupportedException e) {
    10             e.printStackTrace();
    11         }
    12         return null;
    13     }
    14 }
    15 
    16 class Product {
    17     private String productName;
    18     private String productBuildeAddr;
    19     private String productBuildeDate;
    20     //...等一系列关于产品的信息,因为篇幅略过
    21 }
    22 
    23 class Company {
    24     private String companyName;
    25     private String companyAddr;
    26     private String companyMobile;
    27     //...等一系列关于公司的信息,因为篇幅略过
    28 }

    大型公司的信息都比较完善,而且他们都把信息封装到了一个个的对象中去了,订单中展示出了一个个的对象,那为什么我们clone的时候不起作用了呢?我们再来看看客户端的调用:

     1     @Test
     2     public void clien() {
     3         OrderInfo orderInfo = new OrderInfo(new Product("骑士徽章","克利夫兰","20160601"),new Company("骑士公司", "北京骑士大道", "13666666666"));
     4         
     5         OrderInfo cloneInfo = (OrderInfo)orderInfo.clone();
     6         
     7         cloneInfo.getCompany().setCompanyAddr("北京骑士大道2号");
     8         
     9         System.out.println(orderInfo);
    10         System.out.println(cloneInfo);
    11     }

    OrderInfo [productInfo=Product [productName=骑士徽章, productBuildeAddr=克利夫兰, productBuildeDate=20160601], company=Company [companyName=骑士公司, companyAddr=北京骑士大道2号, companyMobile=13666666666]]
    OrderInfo [productInfo=Product [productName=骑士徽章, productBuildeAddr=克利夫兰, productBuildeDate=20160601], company=Company [companyName=骑士公司, companyAddr=北京骑士大道2号, companyMobile=13666666666]]

    我们这里就可以看到了clone订单更改了地址之后,原对象也更改了,这里就涉及到了jvm虚拟中的对象的引用了。(说的简单点就是,其实java中的每个对象在jvm中算是一个引用,引用指向了堆中的对象,而我们在克隆一个对象时,如果进行了浅拷贝的话,那只是将这个引用复制了一次,而没有对这个对象进行克隆,所以会导致,对象的克隆失败,因为两个引用都指向了堆中的同一个对象,所以在这里我们就需要进行deep Clone),这里的deep Clone有两种方式:

    一种就是对需要克隆的对象里面的对象,全部实现clone的方法,那样的话,clone的时候,他就会全部进行复制了,类似上文中的方法

     1 class Product implements Cloneable{
     2     @Override
     3     protected Object clone() {
     4         try {
     5             return super.clone();
     6         } catch (CloneNotSupportedException e) {
     7             e.printStackTrace();
     8         }
     9         return null;
    10     }
    11 }
    12 
    13 class Company implements Cloneable{
    14     @Override
    15     protected Object clone() {
    16         try {
    17             return super.clone();
    18         } catch (CloneNotSupportedException e) {
    19             e.printStackTrace();
    20         }
    21         return null;
    22     }
    23 }

    这里必须注意到的是,如果对象里面还有对象的话,那就必须一直实现Cloneable。

    接下来我们重点介绍第二种方法:流式克隆

    在流式克隆中,我们这边需要使用到Serializable这个接口,这个接口跟Cloneable一样,也是标识接口,这个接口也是空方法,实现了该接口的对象被标识为可序列化的

     1 public class OrderInfo implements Cloneable,Serializable{
     2     private Product productInfo;
     3     private Company company;
     4     
     5     @Override
     6     protected Object clone() {
     7         try {
     8             ByteArrayOutputStream baos = new ByteArrayOutputStream();
     9             ObjectOutputStream oos = new ObjectOutputStream(baos);
    10             oos.writeObject(this);
    11             ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    12             ObjectInputStream ois = new ObjectInputStream(bais);
    13             return ois.readObject();
    14         } catch (IOException e) {
    15             e.printStackTrace();
    16         } catch (ClassNotFoundException e) {
    17             e.printStackTrace();
    18         }
    19         return null;
    20     }
    21 }

    这里对其进行IO操作是使用JVM中的将对象写到流中是对象的一个拷贝的这一个特性,而源对象仍然保留在了jvm中,所以重新读取出来的话又是一条好对象啦,但是这里必须注意的是如果使用流式拷贝的话,那内部所有的被拷贝的对象都要实现Serializable这个接口,只需要实现Serializable接口即可,不需要其他的操作。然后我们再执行客户端的操作就可以看到,客户端得到的是两个不同的对象了。

    现在小陈又解决了一个问题了,现在订单的问题也解决了,也不再会被大量的订单导致出货慢,让客户投诉了,在创业的这段时间遇到了不同的问题,但是小陈有自信可以一步步的解决掉,下回小陈还会遇到什么样的问题呢?

      欲知下回如何,且听下文分解。

  • 相关阅读:
    纯CSS实现的很酷的卡通肖像和眨眼动效
    RMQ(区间求最值)
    CentOS---网络配置具体解释
    breakpoints && lldb  && chisel 的使用
    c语言单链表实现
    hdu1595 find the longest of the shortest(Dijkstra)
    POJ 3254 Corn Fields 状态压缩
    我多希望我学编程时,有人教我这些事!
    tts和字符集的关系--要求源和目的端的数据库字符集必须一样,国家字符集必须一样。
    [读后感]编程能力与编程年龄
  • 原文地址:https://www.cnblogs.com/algorithm-cpp/p/5553531.html
Copyright © 2011-2022 走看看