Builder模式中,为什么必须在对象域而不是builder域中检查参数?
2017-12-11 10:04
211 查看
这个问题仅对于构造不可变类有意义,如果构造可变类,放在哪里都无法保障安全。
使用Builder模式构建不可变类ImmutableObj的实例imObj时,应该把字段的检查放在对象域。可以从两个角度分析:
如果放在builder域(一般是Builder#build()方法中),会存在TOC攻击,即:时刻T1参数检查通过,时刻T2修改其中可变的参数,时刻T3调用构造器,则时刻T3时,参数又变得不合法了。
如果放在对象域(一般是类的构造方法中),还要严格在完成所有字段的初始化之后(初始化之后就不可变了),再检查字段,从而彻底避免TOC攻击。如下:
当然,上述表述有些绝对了:如果参数本身就是不可变的,那么任何时候检查都是可以的。
PS:参数指Builder实例的成员变量,字段指ImmutableObj的成员变量。参数是相对于ImmutableObj的称法。
本文链接:Builder模式中,为什么必须在对象域而不是builder域中检查参数?
作者:猴子007
出处:https://monkeysayhi.github.io
本文基于 知识共享署名-相同方式共享 4.0 国际许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名及链接。
使用Builder模式构建不可变类ImmutableObj的实例imObj时,应该把字段的检查放在对象域。可以从两个角度分析:
如果放在builder域(一般是Builder#build()方法中),会存在TOC攻击,即:时刻T1参数检查通过,时刻T2修改其中可变的参数,时刻T3调用构造器,则时刻T3时,参数又变得不合法了。
如果放在对象域(一般是类的构造方法中),还要严格在完成所有字段的初始化之后(初始化之后就不可变了),再检查字段,从而彻底避免TOC攻击。如下:
public class ImmutableObj { private int[] nums; private ImmutableObj(int[] nums) { this.nums = nums.clone(); // 完成所有字段的初始化后再检查字段 checkArgs(); } private void checkArgs() { if (...illegal...) { throw new IllegalArgumentException("Illegal nums ...: " + Arrays.toString(nums)); } } }
当然,上述表述有些绝对了:如果参数本身就是不可变的,那么任何时候检查都是可以的。
PS:参数指Builder实例的成员变量,字段指ImmutableObj的成员变量。参数是相对于ImmutableObj的称法。
本文链接:Builder模式中,为什么必须在对象域而不是builder域中检查参数?
作者:猴子007
出处:https://monkeysayhi.github.io
本文基于 知识共享署名-相同方式共享 4.0 国际许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名及链接。
相关文章推荐
- Solr4.6,用builder模式构建查询参数对象
- 为什么Java反射对象必须有一个无参数的构造方法?
- 2. 【创建和销毁对象】用构建器创建复杂参数对象(Builder模式)
- 设计技巧20:建造模式:Builder 分不同的步骤创建复杂的对象,支持可变参数
- 拷贝构造函数的参数为什么必须使用引用类型(避免无限递归拷贝,但其实编译器已经强制要求了)
- Android-AlertDialog为什么用builder类创建对象
- 拷贝构造函数的参数为什么必须使用引用类型
- 《Effective Java》builder模式创建对象
- 为什么拷贝构造函数的参数必须是引用?
- C++中类的访问权限针对的是类而不是对象!(为什么类中的函数可以访问对象的私有成员?)
- JS函数的参数对象arguments在严格模式下的限制
- 为什么匿名内部类参数必须为final类型
- Builder生成器(创建型设计模式)面向对象设计模式纵横谈讲座笔记之四
- 匿名内部类调用参数时为什么参数必须是final的
- hibernate3保存对象为什么必须使用事务
- C++ 为什么拷贝构造函数参数必须为引用?赋值构造函数参数也必须为引用吗?
- 为什么使用对象指针而不是使用对象本身?
- 为什么类的拷贝构造函数的参数必须是引用
- 浅谈 memset 函数的第二个参数为什么是 int 而不是 char
- 为什么MVC 不是设计模式