设计模式随笔-原型模式


原型模式

使用场景

原型模式即使用深拷贝生成新的对象,避免重新创建对象所产生的巨大资源消耗

  1. 当某一对象创建耗费资源较大时,推荐使用原型模式实现
  2. new 一个对象过程繁琐,或者需要准备数据付出较大代价时,推荐使用原型模式
  3. 一个对象有多个修改者时,推荐使用原型场景
  4. 需要保存对象快照,供后期使用时(也可通过序列化实现)

实现关键

实体实现Cloneable接口,重写clone方法
注意:
当类存在非基础类型属性时,须在属性类上也实现Cloneable接口,并且类的clone方法需要单独实现属性对象的拷贝赋值,即通过属性类的递归克隆实现类clone方法为深拷贝,避免属性对象产生变化导致的踩内存现象

模式实现

优点

  • 用对象克隆代替对象创建,降低创建对象带来的较大资源开销(空间时间开销大、创建繁琐)

缺点

  • 类clone方法实现须准确,否则修改对象时可能导致同步修改克隆对象的情况
@Data
@Slf4j
@AllArgsConstructor
class Person implements Cloneable {
    private String name;

    private int age;

    /**
     * 该属性非基本类型,实现clone方法时需要单独处理,且该属性的类需要实现Cloneable接口
     * 当该属性类同样有非基本类型属性时,需要递归实现Cloneable接口,重写clone方法
     **/
    private Address address;

    public Person clone() {
        Person person = null;
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
            log.error("Person clone failed");
        }
        if (obj instanceof Person) {
            person = (Person) obj;
        }
        // 为保证深拷贝,需将对象属性进行单独拷贝,然后赋值
        person.setAddress(address.clone());
        return person;
    }

    @Data
    @AllArgsConstructor
    static class Address implements Cloneable {
        private String addressStr;

        public Address clone() {
            Address address = null;
            Object obj = null;
            try {
                obj = super.clone();
            } catch (CloneNotSupportedException e) {
                log.error("Person clone failed");
            }
            if (obj instanceof Address) {
                address = (Address) obj;
            }
            return address;
        }
    }
}

测试用例

@Slf4j
public class PrototypePattern {
    public static void main(String[] args) {
        Person.Address address = new Person.Address("Gansu");
        Person person = new Person("ZhangSun", 18, address);
        Person personClone = person.clone();

        address.setAddressStr("ZheJiang");
        log.info("Person       :{}", JSONObject.toJSONString(person));
        log.info("Person Clone :{}", JSONObject.toJSONString(personClone));
    }
}

1.正确实现clone方法时

2.当以下代码块被注释时,即未对对象属性做特别处理,就会导致修改对象时克隆对象被同步修改的情况出现

// 为保证深拷贝,需将对象属性进行单独拷贝,然后赋值
person.setAddress(address.clone());