Spring中常见的设计模式——原型模式

1、原型模式应用场景

  当遇到大量耗费劳动力的 get,set赋值场景时,如下:

public class SetGetParam {
    public void setParam(UserDto userDto) {
        User user = new User();
        user.setAge(userDto.getAge());
        //...
     userDao.addUser(user);
} }

  原型模式(Prototype pattern)是指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。原型模式主要适用于以下:

  (1)类初始化消耗资源较多;

  (2)使用new 生成一个对象需要非常繁琐的过程(数据准备访问权限等);

  (3)构造函数比较复杂;

  (4)在循环体中产生大量对象;

  在spring中用到的原型模式有:scope="prototype" ,还有常用的JSON.parseObject()也是一种原型模式

2、浅克隆

  创建具体需要克隆的类:

@Data
public class User {
    private String name;

    private Integer age;

    private List<String> hobbies;

    public UserDto clone() {
        UserDto dto = new UserDto();
        dto.setAge(this.age);
        dto.setName(this.name);
        dto.setHobbies(this.hobbies);
        return dto;
    }
}

  创建Client:

public class Client {
    private User user;

    public Client(User user) {
        this.user = user;
    }

    public UserDto startClone(User user) {
        return user.clone();
    }
}

  测试克隆,对比复制过来的值是否有自己的地址,还是用的原来的地址

public class PrototypeTest {
    public static void main(String[] args) {
        //创建具体需要克隆的对象
        User user = new User();
        user.setName("皮肤黝黑的小白");
        user.setHobbies(new ArrayList<>());
        System.out.println(user);
        //创建Client对象,准备开始克隆
        Client client = new Client(user);
        UserDto dto = client.startClone(user);
        System.out.println(dto);
        System.out.println(user.getHobbies() == dto.getHobbies());
        System.out.println(user.getName() == dto.getName());
    }
}

  结果:

User(name=皮肤黝黑的小白, age=null, hobbies=[])
UserDto(name=皮肤黝黑的小白, age=null, hobbies=[])
true
true

  从测试结果可以看出:hobbies和name的内存地址是相同的,这说明我们并没有重新创建对象,这就是浅克隆。

3、深克隆

  采用序列化反序列化克隆,实现深克隆,

@Data
public class UserDeepClone implements Cloneable {
    private String name;

    private Integer age;

    private List<String> hobbies;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return this.deepClone();
    }

    public UserDto deepClone() {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            UserDto dto = (UserDto) ois.readObject();
            return dto;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
public class DeepCloneTest {
    public static void main(String[] args) {
        DeepCloneTest deepCloneTest = new DeepCloneTest();
        UserDeepClone user = new UserDeepClone();
        user.setName("皮肤黝黑的小白");
        user.setHobbies(new ArrayList<>());
        System.out.println(user);
        UserDto dto = null;
        try {
            dto = (UserDto) deepCloneTest.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        System.out.println(dto);
        System.out.println(user.getName() == dto.getName());
        System.out.println(user.getHobbies() == dto.getHobbies());
    }
}

4、克隆破坏单例

  深克隆会破坏单例,其实防御方式很简单,单例类不要实现Cloneable接口即可。

5、ArrayList中clone()方法的源码

    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

 

  

  

posted @ 2019-11-30 11:27  皮肤黝黑的小白  阅读(2371)  评论(0编辑  收藏  举报