8

我正在努力按照 SOLID 原则进行设计。我发现,当您使用“单一责任原则”(SOLID 的 S)时,您通常必须在数据容器和数据处理器之间拆分类。例如,如果我有一个从 DB 读取的具有 5 个属性的类 person,而不是将所有内容都放在一个类中,我将创建一个带有属性的 Person 类和另一个从数据库读取该信息并创建 Person 的 PersonReader 类。

如果我这样做,我必须打开 Person 属性,以便 PersonReader 可以访问它们,但是与将所有内容放在黑盒中并使属性仅可读相比,我的封装更少。

我是否遗漏了什么,或者这是这个原则的一个缺点?

提前致谢

编辑:我已将人员编写器更改为人员阅读器,因为一开始不需要公开属性设置器。

4

4 回答 4

3

大多数数据访问策略(ORM 技术)都涉及您所描述的那种妥协。最少侵入性的使用反射(或内省等)在需要时(例如,当不存在公共设置器时)填充您的实体。

话虽如此,如果您的实体只是数据容器(如在贫血领域模型中),那么单一责任原则不应该让您真正关心,因为您的对象没有会被破坏(或干扰)的复杂逻辑) 数据访问代码。

于 2010-12-10T19:03:54.030 回答
3

也许我遗漏了一些东西,但是你为什么不为 Person 类编写一个接受它所有属性的构造函数呢?这样,PersonReader 将能够创建一个人,而无需您打开该人的属性。

另一种选择是将人员属性的设置器标记为内部(如果 PersonReader 位于不同的程序集中,则使程序集内部对 PersonReader 的程序集可见)。这将允许您访问人员属性,但会阻止任何人在程序集之外更改它们。

于 2010-12-11T10:20:40.890 回答
1

我绝对同意你的观点,有时你会遇到这个问题。我用序列化体验过,类似于ORM。就我而言,我需要将对象的状态写入(二进制)文件。

在某些情况下,创建一个可以写入和读取内部状态的接口可能是合适的。因此,您的 person 类将获得两种方法“保存”和“加载”(或“写入”和“读取”或任何您认为合适的方法)。这些方法分别传递一个“IPropertyWriter”和“IPropertyReader”。(在我的例子中,我称它们为 InStream 和 OutStream)。

Person::save(IPropertyWriter writer) 然后会做

writer.writeProperty("name", this.name);
writer.writeProperty("age", this.age);

你可以争辩说你仍然违反了单一职责原则,但我认为没有人应该知道 Person 的内部结构。(特别是在我的序列化情况下,我必须存储部分无法通过 getter 访问的内部状态)。要点是 Person 不与任何数据库代码耦合。您的 IPropertyWriter 可以是一切。此外,“知道自己的属性”的责任并不是真正的新属性,而是附加到每个对象上。

您也可能会问 Person 改变的可能性有多大。如果不太可能,我认为friend像 C++ 中的类是一个好方法,但如果它可能会改变,我宁愿在声明属性的地方使用序列化方法,这样你就不会忘记更新依赖项代码。

于 2010-12-11T08:45:27.560 回答
0

你想得太细了。一个特定的类应该读取数据库——但你不需要一个唯一的工作是创建一个人的类。那只是浪费。单个数据库阅读器应该能够创建来自数据库的任何类——因为这是它的工作。从数据库中读取。

打开 Person 的属性以便 DatabaseReader 可以访问它们没有封装问题,因为如果没有类能够创建 Person,Person 是多余的。可创建和可破坏是任何类责任的固有部分。

于 2010-12-10T19:26:17.547 回答