如何设计可同时供显示、编辑程序使用且不破坏封装的Shape类对象?
形状类跨程序封装与数据互通设计方案
你倾向的双独立实现方案是可行的,但存在维护冗余的问题,还有第三种更均衡的方案可以选择。
第三种可选方案:接口隔离+访问权限控制的共享库实现
核心思路是把权限控制做在共享库内部,通过接口隔离不同程序的访问权限,具体实现逻辑如下:
- 首先在共享库中定义两套权限不同的接口:
- 给显示程序使用的
IReadOnlyShape公共接口,仅暴露Draw()方法,不提供任何属性修改入口,也不开放内部字段的访问权限 - 给编辑工具使用的
IEditableShape受限接口,继承IReadOnlyShape,额外开放所有可编辑属性的读写权限、以及序列化需要的内部字段访问入口。这部分接口可以通过编程语言的特性限制仅编辑工具可见,比如C#的InternalsVisibleTo特性标注仅编辑工具程序集可访问,C++可以把编辑工具的核心类设为Shape类的友元
- 给显示程序使用的
- 所有Shape的具体实现类统一放在共享库中,内部字段全部设为私有,仅通过上述两个接口暴露对应权限的访问能力
- 序列化、反序列化逻辑统一实现在共享库内部:给显示程序暴露的反序列化方法仅返回
IReadOnlyShape类型的实例,给编辑工具暴露的反序列化方法返回IEditableShape类型的实例
三种方案的适用场景建议
1. 无隔离的共享库方案
除非项目是临时demo且完全没有后续维护需求,否则不建议选择,会破坏封装性,显示程序可以随意修改Shape内部状态,后续迭代很容易出现意料之外的Bug。
2. 双独立实现方案
适合两种程序的Shape逻辑差异极大的场景:比如编辑工具需要支持大量编辑状态、撤销重做等临时字段,显示程序仅需要最简绘制逻辑。选择该方案需要额外补充自动化的序列化格式一致性单元测试,避免两边修改字段定义不同步,导致反序列化出错的问题。
3. 接口隔离共享库方案
是大多数场景下的最优选择,优势非常明显:
- 封装性更强:显示程序拿到的所有Shape实例都是
IReadOnlyShape类型,类型层面就做了隔离,完全感知不到任何可编辑属性,符合你的需求 - 维护成本低:仅需要维护一套Shape实现和序列化逻辑,不会出现两套实现同步修改的冗余工作量
- 兼容性有保障:序列化逻辑统一,不会出现两边实现不一致导致的反序列化异常,能保证显示程序还原的效果和编辑工具保存的完全一致
内容的提问来源于stack exchange,提问作者Johny P.
相关产品推荐
相关产品推荐

