9b27b49608c027749e5abee4a1eb9241
5分钟理解设计模式 —— 原型模式

[TOC]

概述:

  5分钟理解设计模式系列,将通过解决实际问题,来带您理解设计模式,本文希望带您搞懂的2个问题是:

  1. 什么是原型模式?(实际开发案例)
  2. 原型模式的两种实现方法? ## 1.什么是原型模式?(实际开发案例)   原型模式是一种创建型设计模式,Prototype模式允许一个对象在创建另外一个可定制的对象,根本无需知道任何如何创建的细节 我们在实际开发中运用到模型模式,大部分都是因为对象的创建成本过大,比如从数据库、RPC、文件系统、网络中读取的数据,或者经过一系列处理(如数据转换、排序、数据清洗)后得到的数据。   这个时候如果我们使用模型模式、那么我们会节省很多创建对象的成本。   博主的日常开发中,经常会用到模型模式,这里举一个抽象后的工作中的实际案例: 我们有一组房型(Room)信息,用Map进行存储,key为房型id,value为房型。由于房型中的一些属性是需要时时更新的、比如价格、库存、规则。所以说房型数据是一个动态数据,但是获取房型数据的成本很高、数据由各种数据源和接口组合而成,数据量非常大。并且在进行房型操作的时候,是不允许出现中间状态的。更新前是状态A,更新后是状态B,中间不允许出现中间状态。   这个时候,就满足了使用原型模式的特点: 1 数据创建成本高 2 状态B的数据由状态A的数据转化而成,可以通过状态A的原型来创建状态B 3 不允许出现中间状态,所以要求改变状态B的时候,状态A不能改变,并且持续提供服务。 代码如下:
/**
 * 房型.
 *
 * jialin.li
 * 2020-02-23 17:40
 */
public class Room {
    private long id;
    private int price;
    private int inventory;
    private String rule;

    public Room(long id, int price, int inventory, String rule) {
        this.id = id;
        this.price = price;
        this.inventory = inventory;
        this.rule = rule;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public int getInventory() {
        return inventory;
    }

    public void setInventory(int inventory) {
        this.inventory = inventory;
    }

    public String getRule() {
        return rule;
    }

    public void setRule(String rule) {
        this.rule = rule;
    }
}
/**
 * 测试类.
 *
 * jialin.li
 * 2020-02-23 17:40
 */
public class Main {
    public static void main(String[] args) {
        HashMap<Long, Room> roomMap = new HashMap<>();
        Room room = new Room(1,100,3,"一份早餐");
        roomMap.put(room.getId(),room);
        System.out.println("原对象:"+roomMap);
        HashMap<Long, Room> cloneRoomMap = (HashMap<Long, Room>)roomMap.clone();
        System.out.println("克隆对象:"+cloneRoomMap);
    }
}

测试结果:

原对象:{1=jialin.li.Room@2503dbd3}
克隆对象:{1=jialin.li.Room@2503dbd3}

这样做有没有什么问题呢?
  由于我们使用了java中,Object的clone方法,它实现的只是浅拷贝,我们可以从测试结果看出,Map中的对象是同一个,也就是说如果我们修改了该的对象属性,那么两个Map中的对象属性都会被改变,这显然不符合我们的需求,那么有没有解决这个问题的方法呢?接下来我们就要明白什么是浅拷贝、什么是深拷贝。

2. 原型模式的两种实现方法?

原型模式有两种实现方法、分别是浅拷贝深拷贝,示意图如下:

  浅拷贝只会拷贝基本数据类型的数值,如int、long等,以及引用数据类型的内存地址。
深拷贝会将整个对象复制出来,创建一个新的对象。
  由于java中并没有实现深拷贝的api,所以深拷贝往往需要我们自己实现。这里给出两种实现思路

递归拷贝

从上到下,逐层复制。

/**
 * 测试类.
 *
 * jialin.li
 * 2020-02-23 17:40
 */
public class Main {
    public static void main(String[] args) {
        HashMap<Long, Room> roomMap = new HashMap<>();
        roomMap.put(1L, new Room(1, 100, 3, "一份早餐"));
        System.out.println("原对象:" + roomMap);
        HashMap<Long, Room> cloneRoomMap = new HashMap<>();
        for (Map.Entry<Long, Room> roomEntry : roomMap.entrySet()) {
            Room room = roomEntry.getValue();
            long id = room.getId();
            int price = room.getPrice();
            int inventory = room.getInventory();
            String rule = room.getRule();
            cloneRoomMap.put(id, new Room(id, price, inventory, rule));
        }
        System.out.println("克隆对象:" + cloneRoomMap);
    }
}

测试结果:

原对象:{1=jialin.li.Room@2503dbd3}
克隆对象:{1=jialin.li.Room@4b67cf4d}

序列化

先将对象序列化,然后再反序列化成新的对象。具体的示例代码如下所示:

public Object deepCopy(Object object) {
  ByteArrayOutputStream bo = new ByteArrayOutputStream();
  ObjectOutputStream oo = new ObjectOutputStream(bo);
  oo.writeObject(object);

  ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
  ObjectInputStream oi = new ObjectInputStream(bi);

  return oi.readObject();
}

最后,期待您的订阅和点赞,专栏每周都会更新,希望可以和您一起进步,同时也期待您的批评与指正!

© 著作权归作者所有
这个作品真棒,我要支持一下!
一个坚持原创的小专栏。分享编程知识,提升工作效率,致力于通过简单的语言,把编程这点事讲清楚。涵盖内容:java、设...
0条评论
top Created with Sketch.