如何设计不同程序使用的对象?
How to design objects to be used by different programs?
假设:
- 我们有一堆 Shape classes
- 每个形状都有一个 public Draw() 方法并且知道如何绘制自己
- 我们有一个程序,其唯一任务是加载和显示文件中的形状,而不是更改它们
- 我们有一个用于编辑形状 classes 可视化的工具,这意味着一个形状 class 将被绘制到屏幕上,用户可以 select 它并编辑它的数据
- 用户可以将形状序列化到文件中,显示形状的程序应该能够反序列化形状,使其看起来与用户从工具中保存的形状相同
- 形状包含非 public 字段,这些字段决定 public 方法的行为,例如一个 Color 字段,告诉 Draw() 方法用什么颜色绘制形状
- 像这样的字段可以用工具编辑,但显示形状的程序不应该看到
因此,问题是如何实现形状?
- 在两个程序都可以使用的共享库中实现它们会破坏封装,但会有一个实现。
- 编辑器有一个实现,绘制形状的程序有另一个实现,两个实现都应该标准化 de/serialization(相同的成员),这样它们就可以 de/serialized 正确。这解决了封装问题,但我们必须维护两个实现。
如果我不想让绘图程序知道它们可以被编辑,我应该如何设计这些形状对象?
目前我倾向于第二种选择。有没有我没有看到的第三种选择?你有什么建议,为什么?
如果您要在程序之间交换文件,或者可能将它们存储很长时间并在程序更改后稍后加载它们,那么您不只是使用工作对象的默认序列化,它会写出私有字段并在您更改它们时中断。
在这些情况下,数据格式是对象接口的一部分。需要设计并指定。
设计数据格式与设计方法调用接口是不同的工作。您的主要考虑因素通常是:
向后兼容:你将如何确保你现在写入的数据可以被未来的程序使用?这通常由版本控制方案处理。
向前兼容性:您将如何确保未来程序写入的数据对今天的程序尽可能可用?这通常由扩展机制处理。
语言独立性:您是否需要确保处理数据的程序 easy/convenient 是用其他编程语言编写的?这通常意味着您不依赖于您的语言或库定义的复杂序列化格式。
文本、二进制还是介于两者之间?:文本格式(通常基于 JSON、YAML 或 XML)便于调试且易于记录。二进制格式更紧凑。有时您可以使用中间立场。例如,MS Office 文件是打包在 .zip 存档中的文本文件。
假设:
- 我们有一堆 Shape classes
- 每个形状都有一个 public Draw() 方法并且知道如何绘制自己
- 我们有一个程序,其唯一任务是加载和显示文件中的形状,而不是更改它们
- 我们有一个用于编辑形状 classes 可视化的工具,这意味着一个形状 class 将被绘制到屏幕上,用户可以 select 它并编辑它的数据
- 用户可以将形状序列化到文件中,显示形状的程序应该能够反序列化形状,使其看起来与用户从工具中保存的形状相同
- 形状包含非 public 字段,这些字段决定 public 方法的行为,例如一个 Color 字段,告诉 Draw() 方法用什么颜色绘制形状
- 像这样的字段可以用工具编辑,但显示形状的程序不应该看到
因此,问题是如何实现形状?
- 在两个程序都可以使用的共享库中实现它们会破坏封装,但会有一个实现。
- 编辑器有一个实现,绘制形状的程序有另一个实现,两个实现都应该标准化 de/serialization(相同的成员),这样它们就可以 de/serialized 正确。这解决了封装问题,但我们必须维护两个实现。
如果我不想让绘图程序知道它们可以被编辑,我应该如何设计这些形状对象?
目前我倾向于第二种选择。有没有我没有看到的第三种选择?你有什么建议,为什么?
如果您要在程序之间交换文件,或者可能将它们存储很长时间并在程序更改后稍后加载它们,那么您不只是使用工作对象的默认序列化,它会写出私有字段并在您更改它们时中断。
在这些情况下,数据格式是对象接口的一部分。需要设计并指定。
设计数据格式与设计方法调用接口是不同的工作。您的主要考虑因素通常是:
向后兼容:你将如何确保你现在写入的数据可以被未来的程序使用?这通常由版本控制方案处理。
向前兼容性:您将如何确保未来程序写入的数据对今天的程序尽可能可用?这通常由扩展机制处理。
语言独立性:您是否需要确保处理数据的程序 easy/convenient 是用其他编程语言编写的?这通常意味着您不依赖于您的语言或库定义的复杂序列化格式。
文本、二进制还是介于两者之间?:文本格式(通常基于 JSON、YAML 或 XML)便于调试且易于记录。二进制格式更紧凑。有时您可以使用中间立场。例如,MS Office 文件是打包在 .zip 存档中的文本文件。