知识卡片

映射器访问领域对象私有域的四种解法

普通读书笔记卡

内容

数据映射器必须能读写领域对象内部的域,但这些域通常出于封装考虑被设计成私有——领域逻辑本身并不需要把它们公开,可映射器又偏偏需要访问,这是一个没有完美答案的两难问题。作者列出几种权宜解法:一是把数据映射器和领域对象打包在同一个模块单元里(比如Java里放进同一个包),让映射器的可见性局限在包内,但代价是让本不该知道映射器存在的其他代码也间接和这个包产生了依赖关系;二是用反射直接绕过语言本身的访问控制机制,虽然运行较慢,但和一次写错的SQL调用可能造成的代价相比,这点开销通常不值一提;三是提供公开的读写方法,但用一个状态域加以保护——只有在真正处于”数据库加载”这个上下文里调用才被允许,否则抛出异常,并通过刻意选用不像常规getter/setter的方法名,让开发者不会把它们误当成普通存取方法来滥用。这几种方案没有哪个是”标准答案”,作者本人也没有给出斩钉截铁的偏好,需要根据具体语言特性和对可见性/性能/复杂度的取舍来选。可迁移启发:”基础设施层需要突破业务层的封装边界”是一类经常出现的结构性矛盾(映射器要读私有域、序列化框架要读私有字段、测试要注入私有依赖),遇到时不必强求某种”纯粹”的解法,几种务实的折中手段(打包可见性、反射、受保护的公开接口)各有取舍,按场景选就好。

参考来源

- 位置:《企业应用架构模式》第二部分"模式"之"第10章 数据源架构模式"之"10.4.1 运行机制"(源文件:_epub-src/OEBPS/Text/000087.html) - 结论依据:原文说明"映射器需要访问领域对象中的域(属性)。这往往是个问题……可以在打包时将数据映射器与领域对象放在一起……可以使用反射,反射可以绕过语言的可见性原则……或者使用公共方法,但要用一个状态域保护它们,以便当这些方法的使用超出数据库加载的上下文时抛出异常",直接支撑本卡结论。 - 原始内容:这个问题没有简单的解决办法……虽然这比较慢,但如果与错误的SQL调用所耗费的时间相比较,可能也不算慢。