2010-12-10 49 views
8

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

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

我错过了什么或者这是这个原则的缺点吗?

在此先感谢

编辑:我已经改变了人的作家一个人的读者,因为没有必要让属性setter开头公众。

+0

为什么你有一个PersonWriter需要你的Person安装人员公开? – Marcie 2010-12-10 19:07:30

+0

@Marcie:谢谢,这是我的错。我编辑了这个问题。 – 2010-12-10 19:13:05

回答

3

大多数数据访问策略(ORM技术)涉及您所描述类型的妥协。最不侵入的人使用反射(或自省等)在需要时填充实体(例如,当没有公共设置者时)。尽管如此,如果你的实体只是数据容器(如在anemic domain model中),那么单一职责原则不应该真正关心你,因为你的对象没有复杂的逻辑,会被(或干扰)数据访问代码。

+0

谢谢杰夫,但我不认为这是一个贫血的领域模型,因为我没有将领域模型的业务逻辑分开,我从领域模型中取出持久性。我读过的所有东西都会带我走上这条路,只需阅读这里的示例http://p2p.wrox.com/content/articles/design-and-test-driven-development – 2010-12-10 19:16:55

+0

@SoMoS - 对不起,我的意思是说我得到了这种印象是您已经将业务逻辑从领域模型中分离出来(因为您将对象描述为仅仅是容器)。如果是这样的话,我不会对SRP太过挑剔。由于情况并非如此,这是一个公平的问题。 – 2010-12-12 15:14:38

0

你在考虑得太细。一个特定的类应该读取数据库 - 但是你不需要一个只能创建一个Person的类。这只是浪费。单个数据库读者应该能够创建通过数据库的任何类 - 因为这是工作。从数据库中读取。

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

+0

打开一个班级允许其他人修改其数据,当他们不被要求这样做时(甚至更糟糕的是,当他们是公共班级,第三方人员可以使用这些公共班级时,他们不知道他们拥有不应该拥有公共财产 – 2010-12-10 21:33:17

+0

无论如何,我很抱歉,但你的回答与我的问题无关,我可以同意一个读者可以读取所有内容,问题仍然存在,如果读者是只读者在Person类中, – 2010-12-10 21:34:41

+1

@SoMoS:大多数语言都提供了更加细致的控制,在C++中你可以使用“好友”类,而在C#中,你可以使属性成为内部类,并且拥有嵌套类。 ,保护,私人并不是唯一的访问控制。 – Puppy 2010-12-10 22:37:57

1

我绝对同意你,有时你会遇到这个问题。我已经通过序列化来体验它,这与ORM类似。在我的情况下,我需要将对象的状态写入(二进制)文件。

在某些情况下,可以适当地创建一个接口,通过它可以写入和读取内部状态。因此,你的人类会得到两个“保存”和“加载”方法(或者“写”,“阅读”或任何你认为合适的方法)。这些方法分别通过“IPropertyWriter”和“IPropertyReader”。 (在我的情况下,我称他们为InStream和OutStream)。

人::保存(IPropertyWriter作家),然后会做

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

你可以说你还是违反了单一职责原则,但我认为没有人应该知道人的内部。 (特别是在我的序列化的情况下,我不得不通过getters存储部分不可访问的内部状态)。主要的一点是人没有耦合到任何数据库代码。你的IPropertyWriter可以成为一切。此外,“了解自己的财产”的责任并不是真正的新财产,而是无论如何都附属于每一个对象。

你也许会问这个问题人们会改变的可能性有多大。如果不太可能,我认为像C++这样的类是一种好方法,但如果它可能发生变化,我宁愿在声明属性的地方使用序列化方法,以免忘记更新依赖代码。

+0

嗯,这有点复杂,但无论如何一个工作解决方案。我明确将在我的代码中尝试。谢谢! – 2010-12-13 08:22:14

3

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

另一种选择是将人员属性的setter标记为internal(并且如果它在不同的程序集中,则使组件内部对PersonReader的程序集可见)。这将允许您访问人员属性,但会阻止任何人在组件外改变他们。

+0

你是对的,但这是一个简单的例子,真实的情况是关于具有某些在施工时不知道的属性的对象。 – 2010-12-13 08:19:33