防御式拷贝

假设类的客户端会尽其所能来破坏这个类的约束条件,因此你必须保护性的设计程序。
demo:

[java]  view plain  copy
  1. import java.util.Date;  
  2.   
  3. public final class Period {  
  4.     private final Date start;  
  5.     private final Date end;  
  6.     public Period(Date start,Date end) {  
  7.         if(start.compareTo(end) > 0){  
  8.             throw new IllegalArgumentException(start + " after " + end);  
  9.         }  
  10.         this.start = start;  
  11.         this.end = end;  
  12.     }  
  13.       
  14.     public Date start(){  
  15.         return start;  
  16.     }  
  17.       
  18.     public Date end(){  
  19.         return end;  
  20.     }  
  21.     //remainder omitted  
  22. }  
这个类看上去没有什么问题,时间是不可改变的。然而Date类本身是可变的。
[java]  view plain  copy
  1. Date start = new Date();  
  2. Date end = new Date();  
  3. Period period = new Period(start, end);  
  4. end.setYear(78);  
  5. System.out.println(period.end());  
为了保护Period实例的内部信息避免受到修改,导致问题,对于构造器的每个可变参数进行保护性拷贝(defensive copy)是必要的:
[java]  view plain  copy
  1. public Period(Date start,Date end) {  
  2.     this.start = new Date(start.getTime());  
  3.     this.end = new Date(end.getTime());  
  4.     if(this.start.compareTo(this.end) > 0){  
  5.         throw new IllegalArgumentException(this.start + " after " + this.end);  
  6.     }  
  7. }         

保护性拷贝是在检查参数的有效性之前进行的,并且有效性检查是针对拷贝之后的对象,而不是原始对象。


对于参数类型可以被不可信任方子类化的参数,请不要使用clone方法进行保护性拷贝。


通过改变Period:

[java]  view plain  copy
  1. Date start = new Date();  
  2. Date end = new Date();  
  3. Period period = new Period(start, end);  
  4. period.end().setYear(98);  
  5. System.out.println(period.end());  
为了防止二次攻击,可以让end()返回拷贝对象。
[java]  view plain  copy
  1. public Date end(){  
  2.     return new Date(end.getTime());  
  3. }  

但是这样让人写起来很浮躁,所以还是要有一个必要性的把握。


参数的保护性拷贝不仅仅针对不可变类。每当编写编写方法和构造器时,如果他要允许客户提供的对象进入到内部数据结构中,则有必要考虑一下,客户提供的对象是否有可能是可变的,我是否能够容忍这种可变性。特别是你用到list、map之类连接元素时。


在内部组件返回给客户端的时候,也要考虑是否可以返回一个指向内部引用的数据。或者,不使用拷贝,你也可以返回一个不可变对象。如:Colletions.unmodifiableList(List<? extends T> list)


如果类具有从客户端得到或者返回到客户端的可变组件,类就必须保护性的拷贝这些组件。如果拷贝的成本受到限制,并且类信任他的客户端不会进行修改,或者恰当的修改,那么就需要在文档中指明客户端调用者的责任(不的修改或者如何有效修改)。
特别是当你的可变组件的生命周期很长,或者会多层传递时,隐藏的问题往往暴漏出来就很可怕。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Vue 使用 `JSON.parse(JSON.stringify(obj))` 来深拷贝响应数据。但是,这种方法会丢失对象的响应性质,因此需要使用 Vue.set(target, key, value) 或 Vue.delete(target, key) 来重新设置响应性质。 如果数据量很大,建议使用第三方库进行拷贝,如 lodash 中的 _.cloneDeep() 方法。 ### 回答2: 在Vue中,拷贝响应数据可以使用`JSON.parse(JSON.stringify())`的方法。 Vue中的响应数据是通过Vue的响应系统进行管理的,当数据发生变化时,相关的视图会自动更新。然而,有时我们需要对响应数据进行拷贝,这可能是为了进行深层次的修改或者为了保留数据的原始状态等目的。 在拷贝响应数据时,直接使用常见的拷贝方法(如`Object.assign()`、`slice()`等)可能会导致新的对象失去响应功能,也就是说对新对象的修改不会触发相关视图的更新。 为了避免这个问题,我们可以使用`JSON.parse(JSON.stringify())`的方法来进行拷贝。该方法会将对象转换为字符串,然后再将字符串转换回对象,这样可以得到一个全新的对象,而且这个对象不再具有响应功能,但可以进行普通的数据操作。 示例代码如下: ```javascript var originalData = { name: '张三', age: 18 }; var copiedData = JSON.parse(JSON.stringify(originalData)); copiedData.name = '李四'; console.log(originalData); // 输出:{ name: '张三', age: 18 } console.log(copiedData); // 输出:{ name: '李四', age: 18 } ``` 需要注意的是,使用`JSON.parse(JSON.stringify())`进行拷贝时,只能处理简单的对象或数组,对于复杂的对象(例如包含函数、正则表达等),可能会出现意料之外的结果。因此,在进行拷贝操作时,需要谨慎选择合适的方法来保证数据的完整性和正确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值