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);
        }
    }
復制代碼

轉載於:https://www.cnblogs.com/xcgShare/p/11961799.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM